express.Router: Group Routes into Modular Files

express.Router is a mini-app for your routes. It lets you group related endpoints (e.g., all `/users/...` routes) into their own file, keeping your main `app.js` clean. The footgun is forgetting to mount the router in the main app with `app.use()`.
WHY IT EXISTS As an Express application grows, defining all routes in a single server file becomes unmanageable. The file gets long, and finding or debugging a specific endpoint becomes difficult. express.Router was created to solve this scaling problem by allowing developers to break their routes into modular, reusable files.
THE MENTAL MODEL Think of an express.Router as a self-contained plugin or a sub-application. It has its own set of routes and can have its own middleware. You create this mini-app for a specific feature (like 'users' or 'products'), and then you "plug it into" your main Express application under a specific path prefix.
HOW IT WORKS First, you create a new router instance in a separate file, for example, routes/users.js. Inside this file, you import Express and create the router: const router = require('express').Router();. Then, you define routes on the router object instead of the app object: router.get('/:id', ...). Finally, you export the router: module.exports = router;. In your main application file (app.js), you import this router and tell your app to use it with a path prefix: const userRouter = require('./routes/users'); app.use('/users', userRouter);. Now, a request to GET /users/:id is correctly handled by the code in your users.js file.
WHEN TO USE IT Use a router as soon as you have more than a handful of routes or more than one distinct feature in your API. It is the standard, idiomatic way to structure an Express application for long-term maintainability. It's also perfect for applying specific middleware (like authentication) to a whole group of routes at once.
WHEN NOT TO USE IT For a tiny, single-file script or a simple "Hello World" example with only one or two endpoints, creating a separate router is unnecessary overhead. In that limited context, defining routes directly on the app object is simpler and perfectly acceptable.
ONE CANONICAL EXAMPLE In a file named routes/birds.js, you define bird-specific routes: const router = require('express').Router(); router.get('/', (req, res) => res.send('Birds home page')); module.exports = router;. In your main app.js, you mount it: const birds = require('./routes/birds'); app.use('/birds', birds);. A request to your server at /birds now correctly triggers the handler from the separate file.
Read the original → expressjs.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.