Introduction
Middleware functions are the core building block of Express. A middleware function is a function with access to the request object (req), the response object (res), and the next middleware function in the application's request-response cycle, conventionally named next. Middleware can execute code, modify req/res, end the request-response cycle, or call next() to pass control to the next function in the chain. Middleware runs in the exact order it is registered with app.use() or route-specific methods, forming a pipeline that a request travels through before a final response is sent.
Cricket analogy: Each fielder in a relay chain (wicketkeeper to bowler to umpire) touches the ball and decides whether to act or pass it on, just as each middleware handles req/res and calls next() to continue the chain.
Syntax
// Regular middleware
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next(); // pass control to the next middleware
});
// Error-handling middleware (note: 4 arguments)
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong' });
});Explanation
Every regular middleware function has the signature (req, res, next). If it does not call next() and does not send a response (via res.send/res.json/res.end), the request hangs forever — this is the most common middleware bug. Calling next() passes control to the next middleware in the chain; calling next(err) with an argument skips all remaining regular middleware and jumps straight to the nearest error-handling middleware. Error-handling middleware is distinguished purely by arity: it MUST declare exactly four parameters, (err, req, res, next), even if next is unused — Express uses this parameter count to detect it as an error handler. Error-handling middleware should be registered last, after all other app.use() and route calls, so it can catch errors from anything above it.
Cricket analogy: A fielder who catches the ball but never throws it back or runs it in leaves the over stuck forever, just as middleware that never calls next() or sends a response hangs the request indefinitely.
Example
const express = require('express');
const app = express();
// 1. Logging middleware
app.use((req, res, next) => {
console.log('Request received:', req.method, req.url);
next();
});
// 2. Route that may trigger an error
app.get('/risky', (req, res, next) => {
try {
throw new Error('Something broke');
} catch (err) {
next(err); // forward to error-handling middleware
}
});
// 3. Error-handling middleware (must have 4 args)
app.use((err, req, res, next) => {
console.error('Caught error:', err.message);
res.status(500).json({ error: err.message });
});
app.listen(3000);Output
A GET request to /risky logs 'Request received: GET /risky' from the first middleware, then the route handler throws and calls next(err), skipping any remaining regular middleware and invoking the error handler, which logs 'Caught error: Something broke' and responds with status 500 and JSON {"error":"Something broke"}.
Cricket analogy: The umpire logs the delivery bowled, then a no-ball is called mid-over triggering an immediate review referral that skips normal play and goes straight to the third umpire, who logs the ruling and posts the final decision.
Key Takeaways
- Middleware functions have the signature (req, res, next) and run in registration order.
- Forgetting to call next() (when no response is sent) causes the request to hang indefinitely.
- Calling next(err) skips remaining regular middleware and jumps to error-handling middleware.
- Error-handling middleware MUST have exactly 4 parameters: (err, req, res, next) — this arity is how Express identifies it.
- Error-handling middleware should be registered last, after all routes and other middleware.
Practice what you learned
1. What is the correct parameter signature for error-handling middleware in Express?
2. What happens if a middleware function neither calls next() nor sends a response?
3. What does calling next(err) do?
4. In what order should error-handling middleware typically be registered?
Was this page helpful?
You May Also Like
Error Handling in Express
Master synchronous and asynchronous error handling in Express using 4-argument error middleware.
Introduction to Express
Learn what Express is, why it exists on top of Node's http module, and how to create your first Express server.
Routing in Express
Understand how Express matches HTTP methods and URL paths to handler functions using routes.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentSpring Boot Study Notes
Java · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentDjango Study Notes
Python · 30 topics