Skip to content

/glossary/express/middleware

What is middleware in Express?

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated
tool
Express
versions
Express 4.x – 5.x
os
any

Middleware in Express is a function with the signature (req, res, next) that Express calls for each matching request, in the order it was registered with app.use() or a route method. A middleware either ends the response (res.send, res.json) or calls next() to pass control to the next one. Logging, body parsing (express.json()), authentication, CORS and static files are all middleware.

Order of execution

bash
npm init -y >/dev/null
npm install --silent --no-audit --no-fund express@5 >/dev/null 2>&1
cat > app.js <<'EOF'
const express = require("express");
const app = express();
const log = [];
app.use((req, res, next) => { log.push("1 global"); next(); });
app.use("/admin", (req, res, next) => {
  log.push("2 /admin guard");
  if (req.query.key !== "ok") return res.status(401).send("denied");
  next();
});
app.get("/admin/stats", (req, res) => { log.push("3 route"); res.send("stats"); });
app.use((err, req, res, next) => res.status(500).send("error: " + err.message));
const server = app.listen(4402, "127.0.0.1", async () => {
  for (const u of ["/admin/stats", "/admin/stats?key=ok"]) {
    log.length = 0;
    const r = await fetch("http://127.0.0.1:4402" + u);
    console.log(u.padEnd(20), r.status, (await r.text()).padEnd(7), "|", log.join(" -> "));
  }
  server.close();
});
EOF
node app.js

Output

/admin/stats         401 denied  | 1 global -> 2 /admin guard
/admin/stats?key=ok  200 stats   | 1 global -> 2 /admin guard -> 3 route

The guard ends the first request with 401 without calling next(), so the route never runs; in the second request every layer calls next() until the route handler sends the response.

Kinds of middleware

KindRegistered withExample
Application-levelapp.use(fn), app.use("/path", fn)request logging, auth for a path prefix
Router-levelrouter.use(fn) on an express.Router()middleware for one group of routes
Route-levelapp.get("/x", mw1, mw2, handler)validation for one endpoint
Error-handlingapp.use((err, req, res, next) => ...) with four parameterscentral error responses
Built-inexpress.json(), express.urlencoded(), express.static()parse bodies, serve files
Third-partynpm packages such as cors, helmet, morganCORS headers, security headers, logs

Rules that cause most bugs

  • Register middleware before the routes that need it: app.use(express.json()) placed after a route leaves req.body undefined in that route.
  • Call next() exactly once, or send a response; doing neither leaves the request hanging until the client times out.
  • Error handlers need all four parameters (err, req, res, next); with three, Express treats the function as normal middleware.
  • In Express 5, a rejected promise from an async middleware or handler is passed to the error handler automatically; in Express 4 you must call next(err) yourself.

Sources