Look at this URL: /users/42?sort=name&order=asc. Two very different things are happening inside it. 42 identifies which user we're talking about. sort=name&order=asc describes how the response should be shaped — sorted a certain way. Confusing these two — treating an identifier like a filter, or a filter like an identifier — is one of the most common early mistakes when building routes in Express. This guide draws a clear, practical line between them.
What URL Parameters Are
A URL parameter (often called a route parameter) is a named segment built directly into a route’s path, used to identify a specific resource.
/users/:id
Here, :id is a placeholder — when a request comes in for /users/42, Express captures 42 as the value of id. Think of URL parameters as identifiers: they answer the question "which specific thing are we talking about?"
/users/42 → which user /products/17 → which product /orders/1042 → which order
What Query Parameters Are
A query parameter (or query string) is the part of a URL that comes after a ?, made up of key-value pairs, used to filter, sort, or modify a request — not to identify a specific resource.
/users?sort=name&order=asc
Here, sort=name and order=asc are query parameters, separated by &. Think of query parameters as filters or modifiers: they answer the question "how should this response be shaped?" — not "which specific thing."
A simple mental test: if removing the value would make the route meaningless (you can’t fetch “a user” without knowing which user), it’s a URL parameter. If removing it just means “return the default, unfiltered version” (all users, in default order), it’s a query parameter.
Accessing Params in Express
Express captures URL parameters using a colon (:) in the route definition, and makes them available on req.params:
app.get("/users/:id", (req, res) => { const userId = req.params.id; res.send(`Fetching user with ID: ${userId}`); });
Requesting /users/42 results in req.params.id being "42".
Multiple URL parameters
A route can define more than one parameter at once:
Requesting just /products (with no query string at all) still works fine, falling back to the defaults.
When to Use Params vs Query
Use a URL parameter when identifying a specific resource
app.get("/users/:id", ...) // one specific user app.get("/products/:id", ...) // one specific product app.get("/orders/:orderId", ...) // one specific order
If the route doesn’t make sense without a specific value, it belongs in the path as a parameter.
Use a query string when filtering, sorting, or paginating
If the route still makes complete sense without the value — “give me all products,” just unfiltered — it belongs as an optional query parameter.
A practical example combining both
app.get("/users/:id/orders", (req, res) => { const userId = req.params.id; // which user const status = req.query.status; // optional filter: only their pending orders, for example
res.send(`Orders for user ${userId}, filtered by status: ${status || "all"}`); });
Requesting /users/42/orders?status=pending combines both naturally: 42 identifies whose orders, and status=pending filters which of that user's orders to return.
Final Takeaway
URL parameters and query strings both live in the same URL, but they answer two genuinely different questions. A URL parameter says “this route is about this specific thing” — a user, a product, an order — and belongs directly in the path, accessed through req.params. A query string says "shape the response this particular way" — sorted, filtered, paginated — and belongs after the ?, accessed through req.query, typically with sensible defaults for when it's left out. Getting this distinction right from the start makes route design in Express feel obvious instead of arbitrary.
Frequently Asked Questions
Can a single route use both URL parameters and query strings together?
> Yes, and it’s extremely common — a URL parameter identifies the specific resource (like a user), while a query string filters or modifies something about that resource’s related data (like their orders), exactly as shown in the combined example above.
Are URL parameters always required, and query strings always optional?
> As a strong convention, yes — but it’s not a strict technical rule. The practical guideline is: if a route is meaningless without the value, make it a URL parameter; if the route still works sensibly without it (just less filtered), make it a query parameter with a default.
What type is req.params.id — a number or a string?
> Always a string, even if it looks like a number in the URL. If you need to perform numeric operations on it, convert it explicitly (for example, with Number(req.params.id)) before using it.
What happens if I request a route without providing an expected query parameter?
> req.query simply won't include that key at all — accessing it returns undefined, which is exactly why providing a fallback default value (as shown in the pagination example) is a common, sensible practice.
Originally published by Mr Madhukar
Read the complete article on Medium with full formatting & reader responses.