Many real-world resources belong to a parent, comments belong to posts, orders belong to users. This lesson shows how to model that relationship with nested Express routers and the mergeParams option.
What Are Nested Routes?
Nested routes express a parent-child relationship directly in the URL, /users/:userId/posts/:postId, meaning "the post with postId that belongs to the user with userId". Rather than repeating this whole path in one router, Express lets you mount a child router inside a parent one.
The tricky part is that, by default, a nested router cannot see the parent router's route parameters, that's what the mergeParams option solves.
Without { mergeParams: true }, req.params.userId would be undefined inside posts.js, because parameters aren't shared across router boundaries by default.
Nested Router Syntax
const childRouter = express.Router({ mergeParams: true });
parentRouter.use('/:parentId/children', childRouter);
childRouter.get('/', (req, res) => {
// req.params.parentId is available here
});
{ mergeParams: true } makes a child router inherit req.params from its parent router.
Nesting can go more than one level deep for deeply hierarchical resources.
Each level of nesting typically lives in its own router file.
Nested routes still support their own independent middleware.
Nested Routes Cheatsheet
Common nested resource patterns and their URL shapes.
Relationship
URL Pattern
req.params (child)
User's posts
/users/:userId/posts
{ userId }
Post's comments
/users/:userId/posts/:postId/comments
{ userId, postId }
Org's projects
/orgs/:orgId/projects/:projectId
{ orgId, projectId }
A Full Nested Example
Here is a complete, minimal example wiring a user router and a nested posts router together.
Nesting more than two or three levels deep (/a/:aId/b/:bId/c/:cId/d) usually makes URLs harder to read and clients harder to write against. When a sub-resource has a globally unique ID anyway, a flatter top-level route like /comments/:commentId is often simpler.
Common Mistakes
Forgetting { mergeParams: true } and then wondering why a parent's :userId is undefined in the child router.
Nesting resources so deeply that URLs become unreadable and hard for API clients to construct.
Repeating the parent's ID-lookup logic in every nested router instead of centralizing it with router.param().
Mixing up which router the mount path belongs to versus the paths defined inside the child router.
Key Takeaways
Nested routes model parent-child relationships directly in the URL structure.
{ mergeParams: true } is required for a child router to read a parent router's route parameters.
Keep nesting shallow, two or three levels is usually the practical limit.
Each level of nesting can still have its own middleware and validation.
Pro Tip
If you find yourself needing mergeParams more than two levels deep, consider whether a flatter route with a unique ID (/comments/:id) would serve API consumers better than deep nesting.
You now know how to model nested resources with Express routers. Next, learn how to read filtering and pagination data from the URL in the Query Parameters lesson.