Route parameters and the query string
An address often carries data: the post number in /posts/2 or the page number in /posts?page=3. The first is called a route parameter, the second a query string. Express parses both and puts the result into the request object.
Blog data
There is no database yet, so posts are stored in an array. Create the file src/data/posts.js:
// src/data/posts.js
export const posts = [
{ id: 1, title: 'Meet Express', body: 'Express is a web framework for Node.js.' },
{ id: 2, title: 'Routes', body: 'A route connects an address to a function.' },
];A route parameter
A part of the address after a colon becomes a parameter. Its value is in req.params:
// src/app.js
import { posts } from './data/posts.js';
app.get('/posts/:id', (req, res) => {
const id = Number(req.params.id);
const post = posts.find((item) => item.id === id);
if (!post) {
return res.status(404).send('Post not found');
}
res.send(post.title);
});At /posts/2 the page shows "Routes", and at /posts/99 — "Post not found". A parameter value is always a string, so it is converted to a number before comparing.
Several parameters
An address can have several parameters:
// src/app.js
app.get('/posts/:postId/comments/:commentId', (req, res) => {
const { postId, commentId } = req.params;
res.send(`Comment ${commentId} on post ${postId}`);
});/posts/2/comments/5 returns "Comment 5 on post 2".
An optional parameter
In Express 5 an optional part of the address is wrapped in curly braces:
// src/app.js
app.get('/archive{/:year}', (req, res) => {
const year = req.params.year ?? 'all years';
res.send(`Archive: ${year}`);
});The route matches both /archive and /archive/2025.
The query string
Everything after ? in the address is parsed by Express into the req.query object. These values do not need a separate route:
// src/app.js
app.get('/posts', (req, res) => {
const search = req.query.search ?? '';
const found = posts.filter((post) => post.title.includes(search));
res.send(found.map((post) => post.title).join(', '));
});/posts?search=Rou shows only "Routes", and /posts without a query string shows all posts.
Which to choose
| Way | When it fits | Example |
|---|---|---|
| Route parameter | The address of a specific record | /posts/2 |
| Query string | Search, filters, sorting, pages | /posts?page=2&sort=new |
Links are built as plain strings: <a href="/posts/2"> or <a href="/posts?page=2"> in HTML.
Common mistake
Values from req.params and req.query are strings, not numbers. The comparison post.id === req.params.id is always false, because 1 === '1' gives false. Convert the value with Number() and check the result: Number('abc') gives NaN, and there is no point searching for such a post — answer 404 right away.