DEV Community

Sospeter Mong'are
Sospeter Mong'are

Posted on

A Practical Guide to Routes and Routers in Express.js

When you build an API with Express.js, routes are the doors through which requests enter your application, and routers are the architectural wings that organize those doors into clean, manageable sections. Whether you're building a small service or a sprawling backend, mastering routes and routers is essential for clarity, scalability, and maintainability.

This article dives into what routes are, how routers work internally, why modular routing matters, and how to structure a real project using Express routers.


What Are Routes in Express.js?

A route defines how your application responds to a specific HTTP request on a given path.

Each route specifies:

  • a URL path
  • an HTTP method
  • one or more handler functions

Example:

app.get('/users', (req, res) => {
  res.send('List of users');
});
Enter fullscreen mode Exit fullscreen mode

Here:

  • /users is the route path
  • GET is the method
  • The callback function is the route handler

Think of routes as instructions that say:
“Whenever a request comes to this path, using this method, execute this code.”


Route Methods

Express supports all standard HTTP verbs:

app.get('/items', handler);
app.post('/items', handler);
app.put('/items/:id', handler);
app.patch('/items/:id', handler);
app.delete('/items/:id', handler);
Enter fullscreen mode Exit fullscreen mode

There’s also:

app.all('*', handler);  // handles any method
Enter fullscreen mode Exit fullscreen mode

This is useful for catch-all handlers (e.g., global fallbacks).


Route Handlers

A route can have multiple handler functions, creating a mini middleware chain:

app.get('/profile',
  checkAuth,
  checkStatus,
  (req, res) => {
    res.json({ user: req.user });
  }
);
Enter fullscreen mode Exit fullscreen mode

Express executes them in order until a handler sends a response.


Introducing the Express Router

Using app directly for all routes works only for small projects.
Once an application grows, everything becomes tangled.

Enter the Router:

const router = express.Router();
Enter fullscreen mode Exit fullscreen mode

A router is a mini Express application that you attach to the main app. It has:

  • its own middleware
  • its own routes
  • its own configuration

The router helps you break your API into modules.


Why Use Routers?

Routers give you:

1. Better Structure

Group related endpoints together.

2. Clean Separation of Concerns

Authentication routes are not mixed with product routes.

3. Scalability

Routers can be nested and expanded easily.

4. Reusable Middleware

Attach middleware to only one section of your API.


Creating a Router

Example: A router for user-related endpoints.

users.routes.js

const express = require('express');
const router = express.Router();

router.get('/', (req, res) => {
  res.send('All users');
});

router.post('/', (req, res) => {
  res.send('Create user');
});

router.get('/:id', (req, res) => {
  res.send(`User with ID ${req.params.id}`);
});

module.exports = router;
Enter fullscreen mode Exit fullscreen mode

Attach it to your main app:

app.js

const usersRouter = require('./routes/users.routes');

app.use('/users', usersRouter);
Enter fullscreen mode Exit fullscreen mode

Now:

  • GET /users maps to router.get('/')
  • POST /users maps to router.post('/')
  • GET /users/:id maps to router.get('/:id')

Route-Level Middleware Using Routers

You can attach middleware only to a specific router:

router.use(checkAuth);
Enter fullscreen mode Exit fullscreen mode

Or only to a specific route:

router.get('/:id', checkRole('admin'), handler);
Enter fullscreen mode Exit fullscreen mode

This avoids cluttering your entire app with global middleware.


Nested Routers

Routers can be nested to build clean hierarchies.

Example:

/api
   /v1
      /users
      /products
      /orders
Enter fullscreen mode Exit fullscreen mode

In code:

const apiRouter = express.Router();
const v1Router = express.Router();

v1Router.use('/users', usersRouter);
v1Router.use('/products', productsRouter);
v1Router.use('/orders', ordersRouter);

apiRouter.use('/v1', v1Router);

app.use('/api', apiRouter);
Enter fullscreen mode Exit fullscreen mode

This is the structure used by most large production APIs.


Route Parameters

Express makes it easy to capture dynamic URL values:

router.get('/posts/:postId/comments/:commentId', (req, res) => {
  const { postId, commentId } = req.params;
  res.json({ postId, commentId });
});
Enter fullscreen mode Exit fullscreen mode

Route parameters behave like variables within the URL.


Understanding How Express Stores Routes Internally

Express keeps an internal stack in:

app._router.stack
router.stack
Enter fullscreen mode Exit fullscreen mode

Each layer looks like:

{
  route: {
    path: '/users',
    stack: [handlers...],
    methods: { get: true }
  },
  handle: fn
}
Enter fullscreen mode Exit fullscreen mode

Routers store their own stacks and the main app chains them together.
When a request arrives, Express walks through this stack in order, matching the path and method, and executing handlers.


Real Project Folder Structure Example

A clean Express project might look like this:

project/
  app.js
  routes/
    users.routes.js
    products.routes.js
    orders.routes.js
  controllers/
    users.controller.js
    products.controller.js
    orders.controller.js
  middlewares/
    auth.js
    rateLimit.js
    validate.js
Enter fullscreen mode Exit fullscreen mode

Your app.js becomes a simple, readable entry point:

app.use('/users', require('./routes/users.routes'));
app.use('/products', require('./routes/products.routes'));
app.use('/orders', require('./routes/orders.routes'));
Enter fullscreen mode Exit fullscreen mode

This modularization is the hallmark of well-structured Express apps.


Final Thoughts

Routes and routers in Express.js give you the tools to design APIs that are clean, scalable, and organized. While routes define how your app responds to requests, routers allow you to separate concerns and maintain order as your application grows.

Once you adopt router-based organization, your Express apps become easier to understand, maintain, and extend. For large projects, routers aren’t just helpful—they’re essential.

Top comments (0)