URL Parameters vs Query Strings in Express.js
When you're building your first web app with Express.js, you’ll notice that URLs do more than just point to a page—they carry data. But how that data is packed into the URL matters.
In the world of Express, we primarily deal with two types: URL Parameters and Query Strings. Let’s break them down so you know exactly which one to use and when.
Anatomy of a URL
Before diving into params and queries, let's look at what a URL is actually made of. Every URL you type into a browser tells the server where to go and what to bring back.
Think of it this way: the URL parameter is like the house number on a street — it points to a specific thing. The query string is like instructions you give once you're there — "show me only the red ones, sorted by price".
URL Parameters
A URL parameter (also called a "route parameter" or "path parameter") is a named segment in the URL path. It acts as a unique identifier for a specific resource.
Real-world analogy
Imagine a library. Every book has a unique ID number. When you want book number 101, you go directly to shelf 101. The number in the path tells you exactly which thing you want.
// Route definition in Express
app.get('/users/:userId', (req, res) => {
// :userId is a URL parameter
});
// Example URLs that match this route:
// /users/42 → userId = "42"
// /users/alice → userId = "alice"
// /users/99 → userId = "99"
Notice the colon (:) in front of userId — that's how Express knows it's a parameter placeholder, not a fixed path.
Key idea
URL parameters are part of the path itself. If the parameter is missing, the URL doesn't match the route at all. They are required and identify a resource uniquely.
More examples
// Product page
app.get('/products/:productId', ...);
// → /products/shoes-nike-air
// Blog post
app.get('/posts/:slug', ...);
// → /posts/my-first-blog-post
// Multiple parameters in one route
app.get('/users/:userId/orders/:orderId', ...);
// → /users/5/orders/102
Query Strings
A query string comes after the ? in a URL. It holds key-value pairs separated by &. Instead of identifying a resource, query strings filter, sort, or modify what comes back.
Real-world analogy
You're at a restaurant. You order "pasta" (the resource). But then you add: "make it vegetarian, medium spice, no garlic". Those extra instructions are the query string — they shape the result without changing what resource you're asking for.
// URL: /products?category=shoes&sort=price&limit=20
app.get('/products', (req, res) => {
// Query strings are optional — route still matches without them
// /products → works fine (no filters)
// /products?sort=price → also works
});
Key idea
Query strings are always optional. The route works with or without them. They're great for search filters, sorting, pagination, and any time the user can narrow down results.
Key Differences
Here's a side-by-side comparison to make the distinction crystal clear:
| Feature | URL Parameter | Query String |
|---|---|---|
| Position in URL | Inside the path (/path/:id) |
After ? at the end |
| Required? | Yes — route won't match | No — always optional |
| Use case | Identify one thing | Filter or sort things |
| Express access | req.params.name |
req.query.name |
| Multiple values | Use separate route segments | Use & to join pairs |
Accessing Them in Express
Reading URL Parameters — req.params
Express stores URL parameters in the req.params object. The key is whatever you named after the colon in your route definition.
const express = require('express');
const app = express();
// Route definition: :userId is a named parameter
app.get('/users/:userId', (req, res) => {
const id = req.params.userId;
res.send(`Fetching profile for user: ${id}`);
});
// GET /users/42 → "Fetching profile for user: 42"
// GET /users/alice → "Fetching profile for user: alice"
Reading Query Strings — req.query
Express automatically parses the query string and stores everything in req.query. You don't need to do anything special in the route definition.
app.get('/products', (req, res) => {
const category = req.query.category;
const sort = req.query.sort;
const limit = req.query.limit;
res.json({ category, sort, limit });
});
// GET /products?category=shoes&sort=price&limit=20
// → { category: "shoes", sort: "price", limit: "20" }
// GET /products (no query)
// → { category: undefined, sort: undefined, limit: undefined }
Pro tip
Always check if a query value exists before using it — it will be
undefinedif the user didn't include it. Use a default value:const sort = req.query.sort || 'asc';
Using Both Together
The real power comes from combining them. Use a URL parameter to identify which resource, and query strings to control how it's returned.
// URL: /users/42/posts?status=published&page=2
app.get('/users/:userId/posts', (req, res) => {
const userId = req.params.userId; // "42"
const status = req.query.status; // "published"
const page = req.query.page; // "2"
// Translation: "Give me user 42's posts,
// but only the published ones, page 2"
res.json({ userId, status, page });
});
When to Use Which
A simple question helps every time: "Am I identifying a specific thing, or am I filtering/sorting a list of things?"
| Scenario | Use | Example URL |
|---|---|---|
| Get a specific user by ID | URL Param | /users/42 |
| Search users by name | Query String | /users?name=alice |
| Get a specific blog post | URL Param | /posts/my-first-post |
| List posts, sorted by date | Query String | /posts?sort=newest |
| Delete a specific order | URL Param | /orders/99 |
| Filter orders by status | Query String | /orders?status=pending |
| Paginate a results list | Query String | /products?page=3&limit=10 |
The mental model
URL parameters are nouns — they name the thing. Query strings are adjectives — they describe how you want it. "Give me the user (noun) who is currently online (adjective)."
Quick Reference Cheatsheet
| Syntax / Code | What It Does | Example URL | Explanation |
|---|---|---|---|
req.params.id |
Read a URL parameter named id |
/users/123 |
Gets 123 from the URL |
req.query.sort |
Read a query string key named sort |
/users?sort=asc |
Gets asc from query |
/route/:param |
Define a URL parameter in a route | /users/:id |
id becomes dynamic |
/route?key=val |
Send query parameters (no route change needed) | /users?age=25 |
Filters data |
key=a&key2=b |
Multiple query parameters using & |
/users?age=25&city=Pune |
Multiple filters |
You've got it! Here's the one-liner:
Use URL parameters when you need to identify a specific resource — like a user ID or post slug.
Use query strings when you want to filter, sort, or paginate a list of resources.
Both are available in Express via req.params and req.query respectively.
