How the Middleware Stack Works

Every app.use, app.get, app.post and friend pushes a layer onto an ordered array inside the application's router. A layer stores a path pattern, an optional HTTP method, and the function to call. When a request arrives, Express 24,430 walks that array from index 0 and asks two questions of each layer: does the path match, and does the method match? Layers that fail either test are skipped without being called; layers that pass are invoked, and the walk pauses until that function calls next(). The listing registers one layer of each kind and makes each print its name, so the sequence is an observation rather than a claim.

A server whose middleware announce themselvesJavaScript
import express from 'express';
const app = express();
const log = (name) => (req, res, next) => { console.log(`  ${name}`); next(); };
app.use(log('1 app.use          (every request)'));
app.use('/api', log('2 app.use /api     (path-mounted)'));
const books = express.Router();
books.use(log('3 router.use       (inside /api/books)'));
books.get('/:id', log('4 route middleware'), (req, res) => {
  console.log('  5 handler          -> sends response');
  res.json({ id: req.params.id });
});
books.get('/:id/boom', () => { throw new Error('shelf collapsed'); });
app.use('/api/books', books);
app.use((req, res) => {
  console.log('  6 fallback         (no route matched)');
  res.status(404).json({ error: 'Not Found' });
});
app.use((err, req, res, next) => {
  console.log(`  7 error middleware (${err.message})`);
  res.status(500).json({ error: 'Internal Server Error' });
});

Three requests against that server on Express 5.2.1 — one matching a route (200), one matching nothing (404), one throwing (500) — produce this trace:

Output of 20
GET /api/books/42
  1 app.use          (every request)
  2 app.use /api     (path-mounted)
  3 router.use       (inside /api/books)
  4 route middleware
  5 handler          -> sends response
GET /health
  1 app.use          (every request)
  6 fallback         (no route matched)
GET /api/books/42/boom
  1 app.use          (every request)
  2 app.use /api     (path-mounted)
  3 router.use       (inside /api/books)
  7 error middleware (shelf collapsed)

Read the middle trace carefully: /health skips layers 2, 3 and 4 because their mount paths do not prefix it. Nothing is "turned off" — the layers never match. In the third, once a handler throws, Express abandons the rest of the normal chain, including the 404 fallback, and jumps to the first layer registered with four parameters.

A request walking the layer array, skipping unmatched layers and diverting on error
A request walking the layer array, skipping unmatched layers and diverting on error