What is Middleware?
After completing this topic:
You will be able to explain what middleware is, understand the order (pipeline) in which requests are processed in Express, and create and apply your own middleware.
"Middle Processing" between Request and Response
When a request comes to a web server, it doesn't immediately send a response. There are several steps in between.
Request β [Logging] β [Authentication Check] β [Body Parsing] β Route Handler β ResponseEach of these intermediate steps is Middleware. It can be defined as a function that "does something in the middle, between when a request comes in and a response goes out."
Structure of Express Middleware
In Express, middleware is a function that accepts 3 parameters.
function myMiddleware(req, res, next) {
// req: Request object (information sent by the client)
// res: Response object (information the server will send)
// next: Function to pass to the next middleware
console.log(`${req.method} ${req.url}`);
next(); // If you don't call this, the request will stop here!
}
app.use(myMiddleware);next() is key. Calling it is what moves to the next middleware (or route handler). If you forget to call next(), the client will wait forever for a response.
Practical Middleware β Logging, Authentication, Error Handling
Request Logging
app.use((req, res, next) => {
const now = new Date().toISOString();
console.log(`[${now}] ${req.method} ${req.url}`);
next();
});
// [2026-07-03T10:30:00.000Z] GET /usersAuthentication Check
function authGuard(req, res, next) {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ error: 'Login required' });
}
next(); // If the token exists, move on
}
// Apply only to a specific route
app.get('/my-profile', authGuard, (req, res) => {
res.json({ name: 'Kim Hoon' });
});You can apply app.use() to all requests, or you can apply it selectively by placing it as the second argument to a specific route.
Error Handling Middleware
// 4 parameters β Express recognizes this as an error handler
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Server internal error' });
});Error handling middleware has 4 parameters (err added). Express uses this signature to distinguish error handlers. If you call next(err) anywhere in the code, it will arrive here.
Execution Order is the Pipeline
Middleware is executed in the order in which you register it with app.use(). Changing the order will change the behavior.
// 1. Body parsing (first!)
app.use(express.json());
// 2. Logging
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`, req.body);
next();
});
// 3. Route
app.post('/users', (req, res) => {
res.json(req.body);
});
// 4. Error handling (always last)
app.use((err, req, res, next) => {
res.status(500).json({ error: err.message });
});express.json() must be placed before logging so that the parsed data is in req.body. If you change the order, req.body will be undefined. The position of the middleware in the code is its execution order.
Key Takeaways
Middleware is not a complicated concept. It's a pipeline of (req, res, next) functions connected in order. Logging, authentication, parsing, error handling β all the repetitive "intermediate tasks" in a web server are middleware. This concept exists in most web frameworks (Django, Rails, Spring) in addition to Express, so once you understand it, you can apply it anywhere.