What is Middleware

Functions Before the Route Handler

Middleware runs before the router picks a handler. It receives req, res and next. It can read or change the request, end the response early, or call next() to continue. NestJS middleware is the same as Express middleware.

  • It does not know which controller method will run (guards and interceptors do).
  • Forgetting to call next() leaves the request hanging until it times out.
  • Good for: logging, request ids, body parsing, cookies, helmet, CORS, compression.

How next() Works

Example

A middleware chain is a list of functions where each one decides whether to call the next. This is the same algorithm Express uses:

type Req = { url: string; headers: Record<string, string>; id?: string };
type Res = { status: number; body?: string };
type Next = () => void;
type Middleware = (req: Req, res: Res, next: Next) => void;

function run(chain: Middleware[], req: Req, res: Res, final: () => void) {
  let i = 0;
  const next = () => {
    const mw = chain[i++];
    if (mw) mw(req, res, next);
    else final();
  };
  next();
}

let counter = 100;
const requestId: Middleware = (req, _res, next) => { req.id = 'req-' + ++counter; next(); };
const logger: Middleware = (req, _res, next) => { console.log('[' + req.id + '] ' + req.url); next(); };
const maintenance: Middleware = (req, res, next) => {
  if (req.headers['x-maintenance'] === 'on') { res.status = 503; res.body = 'Down for maintenance'; return; }
  next();
};

const scenarios: Record<string, string>[] = [{}, { 'x-maintenance': 'on' }];
for (const headers of scenarios) {
  const res: Res = { status: 200 };
  run([requestId, logger, maintenance], { url: '/products', headers }, res, () => { res.body = 'product list'; });
  console.log('  ->', res.status, res.body);
}

Output

[req-101] /products
  -> 200 product list
[req-102] /products
  -> 503 Down for maintenance