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
reqorres; - either end the response (
res.send()/res.end()), - or pass execution onward by calling
next().
Example:
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 /:
First middleware
Second middleware
Route handler2. 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()
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:
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.
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:
Global middleware
Router middleware5. 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)
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
| Stage | What happens | Example |
|---|---|---|
| 1 | Global middleware (app.use) | logging, JSON parsing |
| 2 | Path-bound middleware (app.use('/path', ...)) | authorization, caching |
| 3 | Middleware and routes inside express.Router() | API endpoints |
| 4 | Specific route handlers (app.get, app.post) | the main code |
| 5 | Error-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:
- Execution runs top to bottom.
- Every middleware must call
next()to pass control onward.- Middleware can be scoped to a path (
app.use('/admin', ...)).- Error handlers (with 4 arguments) run last.
- If a middleware doesn't call
next()and doesn't send a response, the request "hangs".
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.