Skip to main content

Middleware order

1. The basic idea

Express runs middleware in the order they were registered in the code - top to bottom.

That is, the order in your file is the order requests get processed in. Every middleware can:

  • handle part of the request;
  • modify req or res;
  • either end the response (res.send() / res.end()),
  • or pass execution onward by calling next().

Example:

javascript
const express = require('express'); const app = express(); app.use((req, res, next) => { console.log('First middleware'); next(); }); app.use((req, res, next) => { console.log('Second middleware'); next(); }); app.get('/', (req, res) => { console.log('Route handler'); res.send('Done!'); }); app.listen(3000);

Output for GET /:

javascript
First middleware Second middleware Route handler

2. The rule: "everything top to bottom"

Express registers middleware in the order they're written:

  • app.use(), global middleware;
  • app.get(), app.post(), routes;
  • app.use('/path', router), nested routes;
  • app.use((err, req, res, next) => {...}), an error handler (at the end!).

If some middleware doesn't call next() and doesn't end the response (res.send()), the chain stops.

Example: a missing next()

javascript
app.use((req, res, next) => { console.log('1'); // forgot next()! }); app.get('/', (req, res) => { console.log('2'); res.send('OK'); });

The result: Express gets stuck at the first middleware, because next() was never called, the second handler never runs.

3. Middleware bound to paths

You can specify that a middleware applies only to a certain path:

javascript
app.use('/admin', (req, res, next) => { console.log('Middleware for /admin'); next(); }); app.get('/admin', (req, res) => res.send('Admin panel')); app.get('/user', (req, res) => res.send('Profile'));

For GET /admin, the middleware runs → then the route. For GET /user, the /admin middleware is skipped.

4. Router and local middleware

When you mount a router (express.Router()), all the middleware inside it runs within a local context, but the order between global and local middleware is preserved.

javascript
const router = express.Router(); router.use((req, res, next) => { console.log('Router middleware'); next(); }); router.get('/', (req, res) => res.send('The /api route')); app.use((req, res, next) => { console.log('Global middleware'); next(); }); app.use('/api', router);

For a request to /api:

javascript
Global middleware Router middleware

5. Error-handling middleware runs last

Error handlers must come after all regular middleware and routes. Express identifies them by their four arguments: (err, req, res, next)

javascript
app.use((err, req, res, next) => { console.error('Error:', err.message); res.status(500).send('Something went wrong'); });

Express calls them only if you pass an error via next(err) or an exception is thrown inside a middleware.

6. A summary of the execution order

StageWhat happensExample
1Global middleware (app.use)logging, JSON parsing
2Path-bound middleware (app.use('/path', ...))authorization, caching
3Middleware and routes inside express.Router()API endpoints
4Specific route handlers (app.get, app.post)the main code
5Error-handling middleware (app.use(err, req, res, next))final error handling

7. Summary

Express determines middleware execution order by the order they're registered in the code.

The rules:

  1. Execution runs top to bottom.
  2. Every middleware must call next() to pass control onward.
  3. Middleware can be scoped to a path (app.use('/admin', ...)).
  4. Error handlers (with 4 arguments) run last.
  5. If a middleware doesn't call next() and doesn't send a response, the request "hangs".

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.