What is Middleware in Express and How It Works
When building applications with Express, requests usually do not go directly from:
Client → Route Handler → Response
Instead, requests often pass through multiple intermediate functions first.
Examples:
logging requests
checking authentication
validating request data
parsing JSON
handling errors
These intermediate functions are called:
Middleware
Middleware is one of the most important concepts in Express because almost everything in Express works through middleware internally.
Let’s understand how it actually works.
What Is Middleware in Express?
Middleware is a function that runs:
between receiving a request
and sending a response
It acts like a checkpoint in the request lifecycle.
Example mental model:
Request
↓
Middleware
↓
Route Handler
↓
Response
Middleware can:
modify requests
modify responses
stop requests
continue requests
execute additional logic
Middleware as a Request Pipeline
Think of middleware like security checkpoints at an airport.
A request enters the system and passes through multiple checkpoints:
logging checkpoint
authentication checkpoint
validation checkpoint
Each middleware decides:
continue request
reject request
modify request
Only after passing all required checkpoints does the request reach the final route handler.
Basic Middleware Example
Example:
const middleware = (req, res, next) => {
console.log("Middleware Running");
next();
};
Understanding Middleware Parameters
Middleware functions usually receive:
(req, res, next)
| Parameter | Meaning |
|---|---|
req |
Incoming request |
res |
Outgoing response |
next |
Pass control to next middleware |
Where Middleware Sits in the Request Lifecycle
Example flow:
Client sends request
↓
Middleware executes
↓
Another middleware executes
↓
Route handler executes
↓
Response sent back
Requests move through a middleware chain.
Role of next() Function
next() is extremely important.
It tells Express:
“Move to the next middleware or route handler.”
Example:
const logger = (req, res, next) => {
console.log("Request Received");
next();
};
Without next():
request gets stuck
route handler never runs
What Happens Without next()?
Example:
app.use((req, res) => {
console.log("Middleware");
});
Here:
no response sent
no
next()called
The request hangs forever.
Because Express is waiting for the middleware chain to continue.
Using Middleware in Express
Example:
app.use((req, res, next) => {
console.log("Middleware Executed");
next();
});
app.use() registers middleware globally.
This means:
- every request passes through it
Middleware Execution Order
Middleware executes in the exact order it is defined.
Example:
app.use((req, res, next) => {
console.log("First");
next();
});
app.use((req, res, next) => {
console.log("Second");
next();
});
Request flow:
First
Second
Order matters a lot in Express applications.
Request Pipeline Example
Request
↓
Logger Middleware
↓
Authentication Middleware
↓
Validation Middleware
↓
Route Handler
↓
Response
Each middleware performs one responsibility.
Types of Middleware in Express
Express supports multiple middleware types.
1. Application-Level Middleware
Middleware attached directly to the Express app.
Example:
app.use((req, res, next) => {
console.log("App Middleware");
next();
});
Runs for matching requests across the application.
2. Router-Level Middleware
Middleware attached to specific routers.
Example:
router.use((req, res, next) => {
console.log("Router Middleware");
next();
});
Useful for grouping related routes.
Example:
admin routes
auth routes
API routes
3. Built-In Middleware
Express already provides built-in middleware.
Example:
app.use(express.json());
This middleware:
parses JSON request bodies
makes data available inside
req.body
Without it:
- JSON request data would not be parsed automatically
Real-World Middleware Examples
Middleware becomes powerful because it allows reusable request processing.
Example 1: Logging Middleware
app.use((req, res, next) => {
console.log(req.method, req.url);
next();
});
Purpose:
track incoming requests
debugging
monitoring traffic
Example 2: Authentication Middleware
const auth = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return res.status(401).send("Unauthorized");
}
next();
};
Purpose:
protect private routes
verify user identity
Example 3: Request Validation Middleware
const validate = (req, res, next) => {
if (!req.body.email) {
return res.status(400).send("Email Required");
}
next();
};
Purpose:
validate incoming request data
prevent invalid requests
Middleware Can Modify Requests
Middleware can add data to requests.
Example:
req.user = {
id: 1
};
Now later middleware or routes can access:
req.user
This is commonly used in authentication systems.
Middleware Can End Requests Early
Middleware does not always continue execution.
Example:
if (!token) {
return res.status(401).send("Unauthorized");
}
Sometimes middleware blocks requests completely.
Express Middleware Flow Example
app.use(logger);
app.get("/dashboard", auth, (req, res) => {
res.send("Dashboard");
});
Flow:
Request
↓
Logger middleware
↓
Auth middleware
↓
Dashboard route
↓
Response
Why Middleware Is Powerful
Middleware helps:
separate concerns
reuse logic
keep routes cleaner
organize backend architecture
Instead of repeating logic everywhere, middleware centralizes functionality.
Simple Mental Model
Think of middleware like checkpoints on a highway.
Each checkpoint:
inspects request
modifies request
allows request forward
or blocks request completely
Middleware is the core mechanism behind Express request processing.
It sits between:
incoming request
final response
and allows applications to:
process requests step-by-step
organize reusable logic
control request flow cleanly
The key ideas are:
middleware runs in sequence
execution order matters
next()moves the pipeline forward