惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

SecWiki News
SecWiki News
量子位
The Cloudflare Blog
美团技术团队
T
The Exploit Database - CXSecurity.com
博客园 - 【当耐特】
Spread Privacy
Spread Privacy
P
Proofpoint News Feed
C
CXSECURITY Database RSS Feed - CXSecurity.com
博客园 - 三生石上(FineUI控件)
T
Tor Project blog
博客园 - 司徒正美
宝玉的分享
宝玉的分享
T
Threatpost
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
S
Secure Thoughts
T
Threat Research - Cisco Blogs
Hacker News: Ask HN
Hacker News: Ask HN
Jina AI
Jina AI
博客园 - 聂微东
A
Arctic Wolf
I
Intezer
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Know Your Adversary
Know Your Adversary
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
爱范儿
爱范儿
Hugging Face - Blog
Hugging Face - Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
小众软件
小众软件
T
Tailwind CSS Blog
The Hacker News
The Hacker News
L
LINUX DO - 最新话题
Hacker News - Newest:
Hacker News - Newest: "LLM"
WordPress大学
WordPress大学
S
SegmentFault 最新的问题
TaoSecurity Blog
TaoSecurity Blog
Project Zero
Project Zero
博客园 - 叶小钗
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Cloudbric
Cloudbric
雷峰网
雷峰网
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
大猫的无限游戏
大猫的无限游戏
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Troy Hunt's Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
V2EX - 技术
V2EX - 技术
The GitHub Blog
The GitHub Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Privacy & Cybersecurity Law Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
What is Middleware in Express and How It Works
Akash Kumar · 2026-06-25 · via DEV Community

"Middleware is the invisible assembly line your request travels through before it ever reaches your route."


Introduction

You've set up an Express server. You have routes. Things work. But then real-world requirements show up — you need to log every incoming request, verify that users are authenticated, validate request bodies, handle errors gracefully. Where does all that logic go?

The answer is middleware — one of the most powerful and fundamental concepts in Express.js. Once you understand middleware, you stop writing tangled route handlers and start building clean, composable server applications.

This guide walks through what middleware is, how it fits into the request lifecycle, the different types available, and how to use it in practice.


1. What Is Middleware?

In Express, middleware is a function that has access to the request object (req), the response object (res), and a special function called next().

Every middleware function can do one of three things:

  • Execute any code — logging, validation, authentication checks
  • Modify req or res — attach data, set headers, parse a body
  • End the request-response cycle — send back a response and stop
  • Call next() — pass control to the next middleware in line

Think of middleware as a series of checkpoints a request must pass through before it reaches its final destination — your route handler.

// The shape of every middleware function
function myMiddleware(req, res, next) {
  // Do something with the request or response
  console.log("Checkpoint reached!");

  // Then either end the cycle...
  // res.send("Stopped here");

  // ...or pass control to the next middleware
  next();
}


2. Where Middleware Sits in the Request Lifecycle

Every time a client sends a request to your Express server, that request doesn't jump straight to your route handler. It travels through a pipeline — a chain of middleware functions executed in order, one after another.

CLIENT REQUEST
     │
     ▼
┌─────────────────────────────────────────────────────────────┐
│                   EXPRESS APPLICATION                       │
│                                                             │
│  ┌──────────────┐   ┌──────────────┐   ┌────────────────┐  │
│  │  Middleware  │   │  Middleware  │   │  Middleware    │  │
│  │      1       │──►│      2       │──►│       3        │  │
│  │   (logger)   │   │   (auth)     │   │  (validator)   │  │
│  └──────────────┘   └──────────────┘   └────────────────┘  │
│         │                 │                    │            │
│     next() called     next() called        next() called   │
│                                                 │           │
│                                        ┌────────────────┐  │
│                                        │  Route Handler │  │
│                                        │  GET /profile  │  │
│                                        └────────────────┘  │
│                                                 │           │
└─────────────────────────────────────────────────┼───────────┘
                                                  │
                                                  ▼
                                           CLIENT RESPONSE

Each middleware in the chain either passes the baton (calls next()) or ends the race (sends a response). If a middleware doesn't call next() and doesn't send a response, the request just... hangs. That's a bug worth memorizing.

The pipeline analogy: Imagine your request is water flowing through pipes. Each pipe fitting (middleware) can filter it, add something to it, or block it entirely. Your route handler is the tap at the end — it only receives water that made it through every fitting before it.


3. Types of Middleware in Express

Express organizes middleware into four categories. Understanding which type to reach for is key to keeping your code organized.

Application-Level Middleware

This middleware is bound directly to your app instance using app.use() or app.METHOD(). It runs for every request that matches its path (or all requests, if no path is given).

const express = require("express");
const app = express();

// Runs on EVERY incoming request (no path specified)
app.use((req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  next();
});

// Runs only for requests to /dashboard and its sub-paths
app.use("/dashboard", (req, res, next) => {
  console.log("Dashboard section accessed");
  next();
});

When to use it: Global concerns — logging, parsing request bodies, setting security headers — anything that should run across all (or most) routes.


Router-Level Middleware

Router-level middleware works identically to application-level middleware, but it's bound to an Express Router instance (express.Router()). This lets you group related routes and their middleware together into modular units.

const express = require("express");
const router = express.Router();

// Middleware scoped only to this router
router.use((req, res, next) => {
  console.log("User router middleware running");
  next();
});

router.get("/profile", (req, res) => {
  res.send("User profile page");
});

router.get("/settings", (req, res) => {
  res.send("User settings page");
});

// Mount the router on the app
app.use("/users", router);

When to use it: Feature-specific concerns — auth checks that only apply to /admin routes, validation that only applies to /api routes. Keeps your app.js clean and each feature self-contained.


Built-in Middleware

Express ships with a small set of built-in middleware functions that handle common tasks out of the box.

// Parse incoming JSON request bodies
// Attaches parsed data to req.body
app.use(express.json());

// Parse URL-encoded form data (from HTML forms)
app.use(express.urlencoded({ extended: true }));

// Serve static files (HTML, CSS, images) from a directory
app.use(express.static("public"));

These three cover the vast majority of what you need for a standard web application or REST API. Always add express.json() before any route that expects a JSON body — otherwise req.body will be undefined.

When to use it: Body parsing and static file serving. These almost always appear at the top of every Express application.


Error-Handling Middleware

Error-handling middleware has a special signature — it takes four parameters: (err, req, res, next). Express recognizes the four-argument signature and only calls this middleware when an error occurs.

// Must be registered LAST, after all other app.use() and routes
app.use((err, req, res, next) => {
  console.error("Error caught:", err.message);
  res.status(err.status || 500).json({
    error: err.message || "Internal Server Error"
  });
});

To trigger it from anywhere in your application, call next(error) and pass an error object:

app.get("/data", (req, res, next) => {
  try {
    // Something that might fail
    const result = riskyOperation();
    res.json(result);
  } catch (err) {
    next(err); // Skips all regular middleware and jumps to error handler
  }
});

When to use it: Centralizing error responses. Without it, you'd write the same res.status(500) block in every route.


4. Execution Order: Order Is Everything

Middleware in Express runs in the exact order it is registered. This is not a minor implementation detail — it's the defining rule of the middleware system.

const app = express();

app.use((req, res, next) => {
  console.log("Step 1: Logger");
  next();
});

app.use((req, res, next) => {
  console.log("Step 2: Auth check");
  next();
});

app.use((req, res, next) => {
  console.log("Step 3: Request validation");
  next();
});

app.get("/profile", (req, res) => {
  console.log("Step 4: Route handler");
  res.send("Profile data");
});

// Console output for GET /profile:
// Step 1: Logger
// Step 2: Auth check
// Step 3: Request validation
// Step 4: Route handler

A common source of bugs is registering middleware after the routes it's meant to protect. If you put your auth check below your route, it simply won't run for that route.

// ❌ WRONG — auth middleware registered too late
app.get("/secret", (req, res) => res.send("Secret data"));
app.use(authMiddleware); // This never runs for /secret

// ✅ CORRECT — auth middleware registered before the route
app.use(authMiddleware);
app.get("/secret", (req, res) => res.send("Secret data"));


5. The Role of next()

next() is the function that keeps the pipeline moving. Without it, your request stalls permanently.

Middleware calls next()   →  Next middleware runs
Middleware sends response →  Pipeline ends (no more middleware runs)
Middleware does neither   →  Request hangs forever (a bug)

Passing an Error with next(err)

Calling next() with no argument moves to the next regular middleware. Calling next(err) with an argument skips all regular middleware and jumps directly to the nearest error-handling middleware.

// Middleware chain execution paths:

//  next()          ──►  Next regular middleware or route handler
//  next(new Error) ──►  Skips everything → error handler
//  res.send()      ──►  Ends the request-response cycle entirely

function checkApiKey(req, res, next) {
  const apiKey = req.headers["x-api-key"];

  if (!apiKey) {
    // Skip remaining middleware, jump to error handler
    return next(new Error("API key required"));
  }

  // All good — continue down the chain
  next();
}

Always return when calling next() early. Without return, the rest of the middleware function keeps executing after next(), which can cause double-response errors (Cannot set headers after they are sent).


6. Real-World Examples

Logging Middleware

Logs every request with its method, URL, and how long the server took to respond.

function requestLogger(req, res, next) {
  const start = Date.now();

  // Hook into the response finish event to capture response time
  res.on("finish", () => {
    const duration = Date.now() - start;
    console.log(
      `${req.method} ${req.url}${res.statusCode} (${duration}ms)`
    );
  });

  next(); // Always call next — logger should never block a request
}

app.use(requestLogger);

// Output example:
// GET /users → 200 (14ms)
// POST /login → 401 (3ms)
// GET /profile → 200 (22ms)


Authentication Middleware

Checks for a valid JWT token in the Authorization header. Blocks the request with a 401 if invalid, or attaches the decoded user to req.user and continues.

const jwt = require("jsonwebtoken");

function authenticate(req, res, next) {
  const authHeader = req.headers.authorization;

  // Check header exists and has the right format
  if (!authHeader || !authHeader.startsWith("Bearer ")) {
    return res.status(401).json({ error: "No token provided" });
  }

  const token = authHeader.split(" ")[1];

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded; // Attach user data for downstream handlers
    next();
  } catch (err) {
    return res.status(401).json({ error: "Invalid or expired token" });
  }
}

// Applied selectively to protected routes only
app.get("/profile", authenticate, (req, res) => {
  res.json({ message: `Welcome, ${req.user.name}!` });
});

app.get("/settings", authenticate, (req, res) => {
  res.json({ settings: getUserSettings(req.user.id) });
});


Request Validation Middleware

Validates that a request body contains the required fields before it reaches the route handler. Returns a descriptive 400 error if anything is missing.

function validateRegistration(req, res, next) {
  const { name, email, password } = req.body;
  const errors = [];

  if (!name || name.trim().length < 2) {
    errors.push("Name must be at least 2 characters");
  }

  if (!email || !email.includes("@")) {
    errors.push("A valid email address is required");
  }

  if (!password || password.length < 8) {
    errors.push("Password must be at least 8 characters");
  }

  if (errors.length > 0) {
    // Stop here — don't let invalid data reach the route handler
    return res.status(400).json({ errors });
  }

  next(); // Validation passed — continue
}

app.post("/register", validateRegistration, (req, res) => {
  // If we're here, req.body is guaranteed to be valid
  const user = createUser(req.body);
  res.status(201).json(user);
});


Putting It All Together

Here's how a realistic Express application composes all of these middleware types in the correct order:

const express = require("express");
const app = express();

// ── 1. Built-in middleware (always first) ──────────────────────
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// ── 2. Application-level middleware (global) ───────────────────
app.use(requestLogger);

// ── 3. Public routes (no auth required) ───────────────────────
app.post("/register", validateRegistration, registerUser);
app.post("/login", loginUser);

// ── 4. Protected routes (auth required) ───────────────────────
app.use("/api", authenticate);       // All /api/* routes are protected
app.get("/api/profile", getProfile);
app.put("/api/settings", updateSettings);

// ── 5. Error handler (always last) ────────────────────────────
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(err.status || 500).json({ error: err.message });
});

app.listen(3000);


Quick Reference

Middleware Type Bound To Typical Use
Application-level app.use() Logging, body parsing, global auth
Router-level router.use() Feature-scoped logic (admin, API)
Built-in app.use() JSON parsing, static files
Error-handling app.use(err, req, res, next) Centralized error responses
next() Call What Happens
next() Move to the next middleware or route handler
next(err) Skip to the nearest error-handling middleware
res.send() / res.json() End the request-response cycle
Nothing called Request hangs — always a bug

Key Takeaways

  • Middleware functions run in registration order — sequence matters
  • Every middleware must either call next() or send a response — never neither
  • Use return next() to prevent code from continuing after passing control
  • Use next(err) to trigger your centralized error handler
  • Built-in middleware (express.json()) should be registered before any routes that need it
  • Error-handling middleware (err, req, res, next) must always be last

What's Next?

Now that you have a solid foundation in Express middleware, great next steps include:

  • Third-party middlewarehelmet for security headers, cors for cross-origin requests, morgan for production-grade logging
  • express-validator — a dedicated library for request validation with a clean, chainable API
  • Rate limiting — using express-rate-limit to protect routes from abuse
  • Async middleware — wrapping async functions cleanly so errors are always caught

Middleware is the architecture that separates a prototype from a production application. Master the pipeline, and your Express code will be cleaner, safer, and far easier to maintain.


If this clicked for you, the next read is async/await error handling in Express — because try/catch in every route handler is its own kind of callback hell. 🚀