URL Parameters vs Query Strings in Express.js

What URL Parameters Are
A URL parameter is a named placeholder inside a route path that captures a specific segment of the URL. It is part of the path itself, not appended after it.
Consider this URL
GET /users/42
Here, 42 is the value occupying a dynamic segment of the path. In Express, that segment is defined in the route as :id, making 42 the value of the id parameter.
URL parameters represent identity. They point to a specific, individual resource. In the example above, the intent is clear: retrieve the user whose ID is 42. The path would be meaningless without that value.
Other real-world examples
GET /products/keyboard-mechanical -- a specific product
GET /orders/ORD-2026-9981 -- a specific order
GET /posts/how-react-virtual-dom-works -- a specific blog post
In each case, the dynamic segment identifies which resource the client wants. Remove that segment and the request loses its target entirely.
URL parameters are required by definition. A route defined as /users/:id will not match the path /users at all. The parameter must be present for the route to match.
What Query Parameters Are
Query parameters are key-value pairs appended to the end of a URL after a ?. Multiple query parameters are separated by &.
GET /users?role=admin&active=true
Here, role=admin and active=true are two query parameters. They do not change which resource is being accessed. They modify how the request is processed, what data is returned, or how results are filtered.
Query parameters represent options, not identity. In the example above, the client is asking for users, with the additional instruction to filter by role and active status.
Other real-world examples
GET /products?category=electronics&sort=price&order=asc
GET /posts?tag=javascript&page=2&limit=10
GET /users?search=alice
None of these query strings identify a single resource. They describe how to shape or filter the collection being returned.
Query parameters are optional by nature. A route defined as /users will match both /users and /users?role=admin. The absence of a query parameter is handled in the route logic, not by route matching.
Differences Between Them
| Dimension | URL Parameters | Query Parameters |
|---|---|---|
| Location in URL | Inside the path: /users/:id |
After the path: /users?role=admin |
| Purpose | Identify a specific resource | Filter, sort, paginate, or modify results |
| Required | Yes - route will not match without them | No - always optional |
| Accessed via | req.params |
req.query |
| Example | /users/42 |
/users?role=admin |
| Typical use | Resource identity | Search, filter, pagination, configuration |
The clearest way to think about the distinction is this
If removing the value makes the request lose its target, it is a URL parameter.
If removing the value just changes what is returned, it is a query parameter.
A request for /users/42 without the 42 has no meaning. A request for /users without ?role=admin still makes sense - it just returns all users instead of filtered ones.
Accessing URL Parameters in Express
URL parameters are defined in the route path using a colon followed by the parameter name. Express captures the value from the incoming URL and makes it available on req.params.
Defining a Route with a Parameter
app.get('/users/:id', (req, res) => {
const userId = req.params.id;
res.json({ userId });
});
A request to GET /users/42 would produce
{ "userId": "42" }
Note that req.params.id is always a string, even if the value looks like a number. Convert it explicitly when needed
const userId = parseInt(req.params.id, 10);
Multiple Parameters
A route can contain more than one parameter
app.get('/teams/:teamId/members/:memberId', (req, res) => {
const { teamId, memberId } = req.params;
res.json({ teamId, memberId });
});
A request to GET /teams/5/members/99 would produce
{ "teamId": "5", "memberId": "99" }
Each named segment in the path becomes a key on req.params with its corresponding URL value.
Accessing Query Strings in Express
Query parameters require no special route definition. Express parses the query string of every incoming request automatically and exposes it on req.query as a plain JavaScript object.
Reading Query Parameters
app.get('/users', (req, res) => {
const role = req.query.role;
const active = req.query.active;
res.json({ role, active });
});
A request to GET /users?role=admin&active=true would produce
{ "role": "admin", "active": "true" }
Like route params, all query values are strings. If you need a boolean or number, parse the value explicitly
const active = req.query.active === 'true';
const page = parseInt(req.query.page, 10) || 1;
Handling Missing Query Parameters
Because query parameters are optional, always account for the case where a parameter is absent. Use a default value or a conditional check before using the value in logic.
app.get('/products', (req, res) => {
const category = req.query.category || 'all';
const page = parseInt(req.query.page, 10) || 1;
const limit = parseInt(req.query.limit, 10) || 20;
res.json({ category, page, limit });
});
A request to GET /products with no query string would respond with
{ "category": "all", "page": 1, "limit": 20 }
A request to GET /products?category=electronics&page=2 would respond with
{ "category": "electronics", "page": 2, "limit": 20 }
This pattern makes routes flexible without making them fragile.
When to Use Params vs Query
Choosing between URL parameters and query strings is not a matter of preference. There is a practical rule that applies consistently across REST API design.
Use URL Parameters When
You are identifying a specific resource.
If the value is required to locate what the client is asking for, it belongs in the path.
GET /users/42 -- fetch user 42
GET /posts/express-101 -- fetch a specific post
GET /invoices/INV-0091 -- fetch a specific invoice
Omitting the value from the path makes the request ambiguous or unroutable. Express will not even match the route.
Use Query Parameters When
You are modifying, filtering, or configuring how data is returned.
If the value is optional context that shapes the response rather than identifies the resource, it belongs in the query string.
GET /users?role=admin -- filter users by role
GET /products?sort=price&order=asc -- sort products
GET /posts?page=2&limit=10 -- paginate results
GET /logs?from=2024-01-01&to=2024-01-31 -- filter by date range
The route still makes sense without these values. The query parameters are instructions for how to process the request, not what to target.
A Combined Example
Both can appear in the same request when the use case calls for it:
GET /users/42/orders?status=pending&page=1
Here, /users/42/orders uses two URL parameters to identify a specific resource collection - the orders belonging to user 42. The query string then filters that collection to show only pending orders on the first page.
This is a clean and semantically correct URL structure. The path tells Express what is being accessed. The query string tells it how to shape the response.
Conclusion
URL parameters and query strings solve different problems. Parameters identify resources. Query strings configure how those resources are returned.
Getting this distinction right makes your API routes more readable, more predictable, and easier for other developers to consume. It also aligns with how REST APIs are conventionally designed, which reduces friction for anyone working with your endpoints.




