Middleware

The Pipeline Every Request Flows Through

Middleware

Middleware functions run before (and around) your handlers. Auth, logging, body parsing — all middleware.

4 min read Level 2/5 #nodejs#express#middleware
What you'll learn
  • Author a middleware function
  • Chain them with app.use
  • Mount per-route or globally

A middleware is a function (req, res, next) => { ... } that runs in a chain. Each one either calls next() to pass to the next middleware, or sends a response and stops the chain.

Anatomy

function logger(req, res, next) {
  console.log(`${req.method} ${req.url}`);
  next();
}

app.use(logger);

app.use(fn) runs fn before every route handler.

Order Matters — A Lot

app.use(logger);
app.use(requireAuth);
app.use(parseBody);

app.get("/api/users", listUsers);

Logger runs first, then auth, then body parsing, then the route handler. Reverse them at your peril.

Built-in Middleware

import express from "express";

const app = express();

app.use(express.json());                    // parse JSON bodies
app.use(express.urlencoded({ extended: true }));   // form bodies
app.use(express.static("public"));          // serve files

express.json() populates req.body for Content-Type: application/json.

Per-Route Middleware

app.get("/admin", requireAdmin, listAdmins);

// Multiple:
app.post("/api/orders", requireAuth, validateOrder, createOrder);

Middleware between the path and the final handler runs in order for that route only.

A Real-World Auth Middleware

function requireAuth(req, res, next) {
  const token = req.headers.authorization?.replace("Bearer ", "");
  if (!token) {
    return res.status(401).json({ error: "missing token" });
  }
  try {
    req.user = verifyToken(token);
    next();
  } catch {
    res.status(401).json({ error: "invalid token" });
  }
}

app.get("/me", requireAuth, (req, res) => res.json(req.user));

Note: send a response or call next(). Never both.

Error-Handling Middleware

Four args, special signature:

app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).json({ error: "internal" });
});

Mount it last. Errors thrown by handlers (or passed via next(err)) land here.

PackagePurpose
corsCORS headers
helmetSecurity headers
morganRequest logging
compressiongzip / brotli
cookie-parserParse cookies
express-rate-limitThrottle requests

Each app.use(packageName()) and you’re set.

Parsing Request Bodies →