Express Middleware — Complete Guide to Request Processing Pipeline
In this tutorial, you will learn about Express Middleware. We cover key concepts, practical examples, and best practices to help you master this topic.
Express middleware functions access the request and response objects, execute code, modify request/response, and call the next middleware in the pipeline.
What You'll Learn
By the end of this tutorial, you'll use application-level and router-level middleware, create custom middleware, use built-in middleware (json, static, urlencoded), and handle errors with error middleware.
Why Middleware Matters
Middleware is Express's extension mechanism. Logging, authentication, Parsing, compression, and CORS are all implemented as middleware. Understanding middleware lets you customize the request pipeline.
Real-World Use
A production API uses middleware for: request logging, JWT authentication, request body parsing, Rate Limiting, compression, CORS headers, and error handling — all chained in the correct order.
Express Middleware Learning Path
flowchart LR
A[Express Routing] --> B[Middleware]
B --> C[Error Handling]
C --> D[Sessions]
D --> E[Security]
A --> F{You Are Here}
style F fill:#f90,color:#fff
Middleware Fundamentals
import express from "express";
const app = express();
// Custom middleware
const logger = (req, res, next) => {
console.log(`${req.method} ${req.url} at ${new Date().toISOString()}`);
next(); // Pass control to the next middleware
};
app.use(logger); // Applied to all routes
app.get("/", (req, res) => res.send("Hello"));
Application-Level Middleware
// Applied to every request
app.use((req, res, next) => {
req.requestTime = Date.now();
next();
});
// Applied to specific path prefix
app.use("/api", (req, res, next) => {
console.log("API request received");
next();
});
Router-Level Middleware
import { Router } from "express";
const router = Router();
const validateId = (req, res, next) => {
const id = Number(req.params.id);
if (isNaN(id)) return res.status(400).send("Invalid ID");
req.validatedId = id;
next();
};
router.get("/users/:id", validateId, (req, res) => {
res.send(`User ID: ${req.validatedId}`);
});
Built-in Middleware
import express from "express";
const app = express();
app.use(express.json()); // Parse JSON bodies
app.use(express.urlencoded({ extended: true })); // Parse form data
app.use(express.static("public")); // Serve static files
Third-Party Middleware
npm install cors morgan helmet compression
import cors from "cors";
import morgan from "morgan";
import helmet from "helmet";
import compression from "compression";
app.use(helmet()); // Security headers
app.use(cors()); // Cross-origin requests
app.use(morgan("combined")); // HTTP request logging
app.use(compression()); // Gzip compression
Error-Handling Middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(err.status || 500).json({
error: process.env.NODE_ENV === "production"
? "Internal Server Error"
: err.message
});
});
Error middleware has four parameters. Express identifies it by the arity (number of parameters).
Custom Middleware Pattern
const rateLimiter = (maxRequests, windowMs) => {
const requests = {};
return (req, res, next) => {
const ip = req.ip;
requests[ip] = (requests[ip] || 0) + 1;
if (requests[ip] > maxRequests) {
return res.status(429).send("Too many requests");
}
setTimeout(() => requests[ip]--, windowMs);
next();
};
};
app.use(rateLimiter(100, 60000)); // 100 requests per minute
Middleware Order Matters
// WRONG: Error handler before routes
app.use(errorHandler); // Catches nothing
app.get("/test", handler);
// RIGHT: Error handler after routes
app.get("/test", handler);
app.use(errorHandler);
Common Mistakes
1. Forgetting to Call next()
If middleware doesn't call next(), the request hangs until timeout. Always call next() unless sending a response.
2. Sending Response Twice
Calling res.send() or res.json() inside middleware and again in the route handler causes "Cannot set headers after they are sent" error.
3. Wrong Middleware Order
Security middleware should come first. Error middleware should come last. Static files before routes for performance.
4. Not Returning on Error Response
// WRONG: execution continues after send
if (!req.body) res.status(400).send("No body");
// Execution continues here!
// RIGHT: return the send call
if (!req.body) return res.status(400).send("No body");
5. Modifying req/res Objects Without Documentation
If your middleware adds properties to req (like req.user), document it clearly so other developers know what's available.
Practice Questions
1. What is the job of the next() function?
next() passes control to the next middleware in the pipeline. Without it, the request processing stops and hangs.
2. How is error-handling middleware different from regular middleware?
It has four parameters (err, req, res, next) instead of three. Express identifies it by the function's parameter count.
3. What is the order of middleware execution?
Middleware runs in the order it's registered. Request passes through each middleware top-to-bottom until one sends a response.
4. How do you make middleware conditional?
Wrap middleware in a conditional: if (condition) { app.use(middleware); } or use a wrapper function that conditionally calls next().
5. Challenge: Create middleware that adds response time header to every response.
app.use((req, res, next) => {
const start = Date.now();
const originalEnd = res.end;
res.end = function (...args) {
res.set("X-Response-Time", `${Date.now() - start}ms`);
originalEnd.apply(res, args);
};
next();
});
FAQ
Mini Project: Request Logger Middleware
Build a configurable request logger that logs method, URL, status code, duration, and body size.
function requestLogger(options = {}) {
return (req, res, next) => {
const start = Date.now();
res.on("finish", () => {
const duration = Date.now() - start;
const log = {
method: req.method,
url: req.originalUrl,
status: res.statusCode,
duration: `${duration}ms`,
bodySize: res.get("Content-Length") || "0"
};
console.log(options.format === "json" ? JSON.stringify(log) :
`${log.method} ${log.url} ${log.status} ${log.duration}`);
});
next();
};
}
app.use(requestLogger({ format: "json" }));
What's Next
Express Error Handling Express Sessions REST API Express
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro