Understanding Middleware Flow

1. Understanding Middleware Signature

AritySignatureType
3(req, res, next)Standard middleware
4(err, req, res, next)Error-handling middleware
0/2Not recognized as middleware

Example: Standard vs error

app.use((req, res, next) => { req.id = crypto.randomUUID(); next(); });
app.use((err, req, res, next) => { res.status(500).json({ error: err.message }); });

2. Creating Application-Level Middleware

Example: app.use()

// Runs for every request
app.use((req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next();
});

// Path-scoped
app.use("/api", (req, res, next) => { req.scope = "api"; next(); });
FormEffect
app.use(mw)Every request
app.use(path, mw)Path prefix only
app.use(mw1, mw2)Multiple stacked

3. Creating Router-Level Middleware

Example: Router scope

const router = Router();
router.use(requireAuth);
router.use((req, res, next) => { req.tenant = req.user.tenant; next(); });
ScopeMethod
Appapp.use()
Routerrouter.use()
Routeapp.get(path, mw, handler)

4. Using Built-in Middleware

MiddlewarePurpose
express.json([opts])Parse JSON bodies
express.urlencoded([opts])Parse application/x-www-form-urlencoded
express.raw([opts])Buffer body (e.g., webhooks)
express.text([opts])Plain text body
express.static(root, [opts])Static files
express.Router([opts])Mountable route group

5. Implementing Third-Party Middleware

PackageRole
helmetSecurity headers
corsCORS
compressiongzip/brotli
morganHTTP request logger
cookie-parserCookie parsing
express-sessionSessions
express-rate-limitRate limiting
passportAuthentication
multerFile uploads

6. Creating Custom Middleware Functions

Example: Request ID + duration

export function requestId() {
  return (req, res, next) => {
    req.id = req.headers["x-request-id"] || crypto.randomUUID();
    res.setHeader("X-Request-Id", req.id);
    next();
  };
}

export function duration(logger) {
  return (req, res, next) => {
    const start = process.hrtime.bigint();
    res.on("finish", () => {
      const ms = Number(process.hrtime.bigint() - start) / 1e6;
      logger.info({ id: req.id, ms, status: res.statusCode });
    });
    next();
  };
}

app.use(requestId(), duration(logger));

7. Using Middleware for Specific Routes

Example: Per-route stacks

app.post("/upload", auth, multer().single("file"), validateFile, (req, res) => {
  res.json({ filename: req.file.originalname });
});
PatternUse
InlineSpecific to one route
ArrayReusable group: const adminMW = [auth, requireAdmin]

8. Executing Multiple Middleware

        ┌──────┐  next()  ┌──────┐  next()  ┌─────────┐
req ──▶ │ MW 1 │ ───────▶ │ MW 2 │ ───────▶ │ Handler │ ──▶ res
        └──────┘          └──────┘          └─────────┘
                              │
                              └─ next(err) ──▶ Error MW
        

9. Calling next() Function

CallEffect
next()Pass to next middleware
next(err)Skip to error handler
next("route")Skip to next matching route
next("router")Skip remaining router middleware
(no call)Hangs forever — must terminate response
Warning: Calling next() AND res.send() in the same middleware causes "Cannot set headers after they are sent" errors.

10. Skipping Remaining Middleware

Example: next("route") to bypass

app.get("/users/:id",
  (req, res, next) => {
    if (req.params.id === "0") return next("route");  // skip handler below
    next();
  },
  (req, res) => res.json({ id: req.params.id })
);

app.get("/users/:id", (req, res) => res.json({ id: "fallback" }));

11. Understanding Middleware Order

RuleDetail
Top-downOrder of app.use() calls determines execution
Body parsers firstBefore any route that reads req.body
Static lastBefore 404 handler
Error handler LASTMust be after all routes