Middleware functions are functions that have access to the request object (req), the response object (res), and the next function in the application’s request-response cycle. These functions can:
- Execute any code.
- Make changes to the request and the response objects.
- End the request-response cycle.
- Call the next middleware in the stack.
Think of middleware as an assembly line for your HTTP requests. Each station on the line (a middleware function) does something to the request before passing it along to the next station.
The next() Function
The most crucial concept in middleware is the next() function. When you call next(), you are passing control to the next middleware function in the line. If you don't call next() (or end the request by sending a response), the request will be left hanging, and the client will time out.
Types of Middleware
- Application-level middleware: Bound to the app object using app.use() or app.METHOD().
- Router-level middleware: Works the same as application-level, but it is bound to an instance of express.Router().
- Error-handling middleware: Has a special signature with four arguments (err, req, res, next).
- Built-in middleware: Standard middleware that comes with Express, like express.json() and express.urlencoded().
- Third-party middleware: Middleware installed from NPM, like helmet or cors.
Using Built-in Middleware
A common task is parsing the body of incoming requests. The express.json() middleware does this for you. It parses incoming requests with JSON payloads and makes the resulting object available on req.body.
JavaScript
const express = require('express');
const app = express();
// This is a built-in middleware.
// It must be placed BEFORE your routes that need to process JSON.
app.use(express.json());
app.post('/api/data', (req, res) => {
// Thanks to express.json(), req.body contains the parsed JSON data
const data = req.body;
console.log('Received data:', data);
res.json({ message: 'Data received!', yourData: data });
});
app.listen(3000, () => console.log('Server running...'));
Writing a Custom Middleware
Let's create a simple logger middleware that prints the HTTP method and URL of every incoming request to the console.
JavaScript
const express = require('express');
const app = express();
// Custom middleware function
const requestLogger = (req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
next(); // Pass control to the next middleware/route handler
};
// Apply the custom middleware to all routes
app.use(requestLogger);
// --- Routes ---
app.get('/', (req, res) => {
res.send('Homepage');
});
app.get('/about', (req, res) => {
res.send('About Us');
});
app.listen(3000, () => console.log('Server running...'));
Now, every time you make a request to your server, you'll see a log line in your terminal, like [2025-09-23T08:30:00.000Z] GET /about. This demonstrates how middleware can be used to handle cross-cutting concerns for all your routes.