How to Use Express Router for Clean, Modular APIs
Learn how Express Router lets you group routes, attach route‑specific middleware, and keep your main app file tidy. Follow a step‑by‑step example, discover common mistakes, and see when a router is overkill.
24 Dec 2025, 18:51 UTC

Why Use Express Router?
When an Express app grows, the app.js file can become a tangled list of route handlers. Express Router lets you split related endpoints into separate modules, each with its own middleware stack. The result is a cleaner main file, easier maintenance, and the ability to reuse route groups across projects.
The Core Idea
Think of a router as a mini‑application that only knows how to handle a subset of paths. It can:
- Define routes like
router.get('/users', …). - Attach middleware that runs only for its routes.
- Be exported and mounted under a base path in the main app.
Setting Up a Router Module
Create a file apiRouter.js in the root of your project.
// apiRouter.js
const express = require('express');
const router = express.Router();
// Route‑specific middleware – runs before any route in this router
router.use((req, res, next) => {
console.log(`[API] ${req.method} ${req.originalUrl}`);
next();
});
// Example route
router.get('/users', (req, res) => {
res.json({ users: [] });
});
module.exports = router;
Key points:
express.Router()creates an isolated routing instance.- The
router.usemiddleware runs only for routes inside this router. - Export the
routerobject so it can be required elsewhere.
Mounting the Router in the Main App
In your main app.js (or server.js), import the router and mount it under a base path:
// app.js
const express = require('express');
const app = express();
const apiRouter = require('./apiRouter');
// Mount all routes from apiRouter under /api
app.use('/api', apiRouter);
// A simple root route to confirm the server is running
app.get('/', (req, res) => res.send('Hello World!'));
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Server listening on port ${PORT}`));
Running node app.js will expose the user endpoint at http://localhost:3000/api/users. The console will log each request because of the router‑specific middleware.
Common Pitfalls and Limits
- Forgot to export the router –
require('./apiRouter')returnsundefined, causing a runtime error whenapp.useis called. Always addmodule.exports = router;. - Mounting without a base path –
app.use(apiRouter)places its routes at the root, potentially clashing with other routes. Use a clear prefix like/api. - Over‑engineering – creating a router for a single trivial route adds unnecessary files and can confuse developers. Use routers when you have at least a handful of related endpoints.
- Middleware order – router middleware runs after any
app.usemiddleware that precedes the mount. If authentication must run before all routes, place it inapp.jsbefore mounting. - Stateful routers – routers are stateless; avoid storing request‑specific data in the router object. Use
reqor session storage instead.
Practical Verification
After setting up, verify with a simple curl:
curl -i http://localhost:3000/api/users
You should see a 200 status and a JSON body. If you get a 404 or a server error, check that:
- The router file is named correctly and located in the same directory as
app.js. - The export statement is present.
- The mount path (
/api) matches the request URL.
When to Use a Router
Typical scenarios:
- Grouping CRUD endpoints for a resource (e.g.,
/products). - Separating public vs. authenticated routes.
- Reusing the same router in multiple microservices.
Avoid routers for isolated routes that don’t share middleware or logical grouping. Keep the codebase simple.
Conclusion
Express Router is a lightweight, declarative way to keep your route definitions organized. By exporting routers, attaching route‑specific middleware, and mounting them under clear prefixes, you maintain a clean app.js and enable reusable API modules. Remember the common pitfalls—exporting, base paths, and over‑splitting—to keep your application stable and maintainable.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.