What is Middleware in Express and How It Works

Think of middleware as "assembling line worker" in your web server. In express a request doesn't just hits the route and instantly get a request. It usually passes throught the several layers of code that can inspect, transform, or even reject this request before it reach its final destination.
What Middleware Is in Express
At its core, a middleware is just a function has access to the request req object, a response res object and the next middleware function in the application request - response cycle.
A middleware funciton can:
- Execute any code
- Make changes to the request and response object
- End the request and response cycle
- Call the next middleware in the stack using
next()method
Where Middleware Sits in Request Lifecycle
Middleware lives in the middle between the moment the server recieve request from the client and the movment the server sends back a final resposne.
When a reqeust comes in, Express move it through the pipeline. If a middleware function doesn't end the cycle (by sending a response), it must pass control to the next function. If it doesn't do either, the request will simply hang and the client will eventually timeout.
Types of Middleware
Application Level Middleware
Thses are bound to the instance of the app object using app.use() or app.method() (where method is get, post etc.). They applye to the entire application or a specific paths across the app.
const app = express();
app.use((req, res, next) => {
console.log("Time:", Date.now());
next();
});
Router-level middleware
This works exactly like application level middleware, except it is bound to the express route express.Router(). This is useful for modularizing your code like all /api/users route having a specific auth middleware.
const router = express.Router();
router.use("/user/:id", (req, res, next) => {
console.log("Request Type:", req.method);
next();
});
Built-in mmiddleware
Express comes with a few built in functions, so you don't have to re-invent the wheel for a common tasks.
express.json(): parse incoming requests with json payload.express.urlencoded(): parse incoming requests with url-encoded payloads.express.static(): servers static assets like html, image etc.
Execution Order of Middleware
Middleware exection is top down. The order in which you defined your middleware in your code is excatly the order in which they execute.
If you place a logging middleware at the top of your file, it will log every single requests. If you place it after a route handler that sends a response, that middleware will never run for that route because the cycle will already terminated.
Role of next() Function
The next() function is the "baton" in a relay race. When called, it tell express to move to the successeding middleware function in the stack.
Parsing Control: if you dont call
next(), the next function in the chain never executed.Error Handling: if you pass an argument to the
next(), likenext(err), express skipp all remaining non-error handling middleware and jump straight to the error handling middleware.
Real-world Examples
1. Logging
Logging is the most common use case, it allow you to see who is visiting your site and what are they doing.
app.use((req, res, next) => {
console.log(`\({req.method} request received at \){req.url}`);
next();
});
2. Authentication
You can protect routes by checking if a user is logged in before them to processed to the sensitive data.
const protect = (req, res, next) => {
if (req.headers.authorization === "secret-token") {
next(); // User is authenticated
} else {
res.status(401).send("Unauthorized"); // Stop the cycle here
}
};
app.get("/dashboard", protect, (req, res) => {
res.send("Welcome to your dashboard");
});
3. Request validation
Before processing data (like user registration), middleware can check if the incomming data is valid.
app.post(
"/register",
(req, res, next) => {
if (!req.body.email || !req.body.password) {
return res.status(400).send("Missing email or password");
}
next();
},
(req, res) => {
// Logic to save user to database
res.send("User registered!");
},
);
Summary
Express middleware functions act as an intermediary pipeline between a client’s request and the server’s final response. They have full access to the req and res objects, allowing them to modify data, execute code, or terminate the cycle early.
Key types include Application-level (global), Router-level (modular), and Built-in (e.g., express.json). Execution follows a strict top-down order, managed by the next() function, which hands off control to the subsequent handler. If next() isn't called, the request hangs. This pattern is fundamental for managing authentication, logging, and input validation cleanly and efficiently before reaching the core application logic in modern web apps.




