URL Parameters vs Query Strings in Express.js

Search for a command to run...

No comments yet. Be the first to comment.
You open WhatsApp, type a message, and hit send. A single grey tick appears. You're on a train with no signal, but the message went through anyway. Or did it? That single tick is the beginning of a su

You record a Reel, add a song, trim it, and then close the app before posting. When you reopen Instagram, the draft is right there waiting. Nothing was lost. That experience feels simple. The system b

If you have built a React Native app, you have felt the pain of navigation setup. It is easy to get wrong and hard to keep clean as apps grow. This article explains what routing means, why it matters,

Modern apps are not just a pile of screens. They are a living system of features, data flows, offline behavior, and performance constraints. If you have only shipped small apps, the jump to something

Your application has user accounts. Some routes should only be accessible to logged-in users. How do you protect routes and verify that a request actually comes from who they claim to be? JWT (JSON We

Ashish's Blog
57 posts
Your API needs to receive data from users. Express lets you pass data through the URL in two different ways: URL parameters and query strings. They look different, work differently, and have different purposes.
URL parameters are placeholders in the route path. They're required and define the resource you're accessing.
Consider these examples:
/users/123 - get user with ID 123
/posts/456/comments - get comments for post 456
/products/789/reviews - get reviews for product 789
The numbers and identifiers are URL parameters. They identify which specific resource you want.
In Express, you define parameters with a colon:
import express from 'express';
const app = express();
app.get('/users/:id', (req, res) => {
const userId = req.params.id;
res.json({ message: `Getting user ${userId}` });
});
app.get('/posts/:postId/comments/:commentId', (req, res) => {
const postId = req.params.postId;
const commentId = req.params.commentId;
res.json({ postId, commentId });
});
app.listen(3000);
When a request comes in, Express extracts the parameter values and places them in req.params.
Usage examples:
GET /users/123 → req.params.id = "123"
GET /posts/456/comments/789 → req.params.postId = "456", req.params.commentId = "789"
Query strings come after a question mark in the URL. They're optional and add filtering or modification options.
Consider these examples:
/users?role=admin - filter users by role
/products?sort=price&limit=10 - sort by price, limit to 10 results
/search?q=node&lang=en - search for "node" in English
In Express, query strings are available in req.query:
import express from 'express';
const app = express();
app.get('/users', (req, res) => {
const role = req.query.role;
const status = req.query.status;
res.json({ message: `Getting users`, role, status });
});
app.get('/search', (req, res) => {
const q = req.query.q;
const limit = req.query.limit;
res.json({ search: q, limit });
});
app.listen(3000);
Usage examples:
GET /users?role=admin → req.query.role = "admin"
GET /search?q=javascript&limit=20 → req.query.q = "javascript", req.query.limit = "20"
| Aspect | URL Parameters | Query Strings |
|---|---|---|
| Purpose | Identify resource | Filter/modify results |
| Required | Yes | No |
| Syntax | /users/123 |
/users?role=admin |
| Express | req.params |
req.query |
| Example | Get specific user | Get users matching criteria |
| Multiple values | Hard to add | Easy with & |
URL Parameters: Identify the exact resource you want
app.get('/users/:id', (req, res) => {
// GET /users/123
// Retrieve THE user with ID 123
});
app.get('/posts/:postId/comments/:commentId', (req, res) => {
// GET /posts/456/comments/789
// Get specific comment 789 in specific post 456
});
Query Strings: Filter or modify what you're retrieving
app.get('/users', (req, res) => {
// GET /users?role=admin&status=active
// Get all users, but filter by role and status
});
app.get('/posts', (req, res) => {
// GET /posts?sort=date&limit=10&skip=20
// Get posts, sorted by date, 10 per page, starting from position 20
});
You can use both parameters and query strings together:
import express from 'express';
const app = express();
app.get('/users/:id/posts', (req, res) => {
const userId = req.params.id;
const sort = req.query.sort;
const limit = req.query.limit;
res.json({
message: `Getting posts for user ${userId}`,
sort,
limit
});
});
app.listen(3000);
Examples:
GET /users/123/posts → User 123's posts
GET /users/123/posts?sort=date → User 123's posts sorted by date
GET /users/123/posts?sort=date&limit=10 → User 123's 10 most recent posts
When you have multiple query parameters, separate them with &:
app.get('/search', (req, res) => {
const query = req.query.q;
const lang = req.query.lang;
const category = req.query.category;
res.json({ query, lang, category });
});
Usage:
GET /search?q=javascript&lang=en&category=tutorial
→ query = "javascript", lang = "en", category = "tutorial"
You can pass multiple values for the same parameter:
app.get('/products', (req, res) => {
const colors = req.query.color;
res.json({ colors });
});
Usage:
GET /products?color=red&color=blue&color=green
→ colors = ["red", "blue", "green"]
Query parameters always come as strings. If you need numbers, convert them:
import express from 'express';
const app = express();
app.get('/products', (req, res) => {
const limit = parseInt(req.query.limit) || 10;
const skip = parseInt(req.query.skip) || 0;
res.json({ limit, skip });
});
app.listen(3000);
Without conversion, req.query.limit is the string "20", not the number 20.
Use URL parameters when:
Identifying a specific resource
The value is required
Following REST principles for resource identification
Examples: user ID, post ID, product ID
Use query strings when:
Filtering results
Sorting or paginating
The value is optional
Adding modifiers or options
Examples: role, category, sort order, page number
A well-designed REST API uses both appropriately:
import express from 'express';
const app = express();
// Get all users (with optional filters)
app.get('/users', (req, res) => {
const role = req.query.role;
const status = req.query.status;
// Retrieve users, optionally filtered by role and status
});
// Get specific user
app.get('/users/:id', (req, res) => {
const userId = req.params.id;
// Retrieve specific user by ID
});
// Get posts for a specific user (with optional sorting)
app.get('/users/:userId/posts', (req, res) => {
const userId = req.params.userId;
const sort = req.query.sort;
// Retrieve posts for user, optionally sorted
});
// Get specific comment on specific post by specific user
app.get('/users/:userId/posts/:postId/comments/:commentId', (req, res) => {
const { userId, postId, commentId } = req.params;
// Retrieve specific comment
});
app.listen(3000);
Mistake 1: Using parameters when query strings make sense
// Wrong - parameters for filters
app.get('/users/:role/:status', (req, res) => {
// URL becomes /users/admin/active
// Hard to add more filters
});
// Better - query strings for filters
app.get('/users', (req, res) => {
// URL is /users?role=admin&status=active
// Easy to add/remove filters
});
Mistake 2: Forgetting to convert query parameters to numbers
app.get('/products', (req, res) => {
const limit = req.query.limit; // This is a string!
const results = db.getProducts().slice(0, limit);
// limit as string might not slice correctly
});
URL parameters identify a specific resource and go in the route path
Query strings are optional filters and go after the question mark
Parameters are required and part of the route definition
Query strings are optional and make URLs flexible
Access parameters via req.params and query strings via req.query
Combine both for powerful, flexible APIs
Use parameters for identification, query strings for filtering
Mastering both gives you the tools to build flexible, standard REST APIs that users can intuitively understand.