Skip to main content
Middleware is one of the most important Express concepts. Every request flows through a chain of middleware functions before reaching the final route handler. This page covers built-in middleware, popular third-party packages, custom middleware, error handling, and how to organize large applications using Express Router.

What Is Middleware?

Middleware is a function that runs between an incoming request and the outgoing response. It has access to req, res, and next.
The middleware chain works like this:
If a middleware does not call next() AND does not send a response, the request hangs forever. The client waits until a timeout. Always ensure one or the other happens.

The Middleware Chain: next() Explained

1

Request arrives

Client sends HTTP request to the server.
2

First middleware runs

Express calls it with req, res, and next.
3

Call next() or end the response

If next() is called, execution moves to the next middleware. If res.send() is called, the cycle ends.
4

Route handler runs

Eventually a route matches and processes the request.
5

Response sent

The handler sends the response back to the client.

Built-in Middleware

express.json() must be registered BEFORE routes that read req.body. Without it, req.body is undefined.

Third-Party Middleware

Install all three:

Writing Custom Middleware

Request Logger

Request Timer

Authentication Check Middleware

Error-Handling Middleware

Error middleware is special: it has 4 parameters instead of 3. Express detects it by the 4-arg signature.
Error-handling middleware must be registered LAST in app.js, after all routes. Otherwise errors from routes cannot reach it.
To trigger it from a route:

Express Router

Use express.Router() to organize routes in separate files. This keeps app.js clean.
Mount in app.js:
Now all user routes are accessible at /api/v1/users.

Route Parameters vs Query Strings

Chaining Middleware on Routes

You can chain multiple middleware functions before the route handler:

API Versioning

Prefix all routes with a version number from day one:
This lets you change v2 without breaking clients still using v1.

Complete app.js Structure

Key Terms

Common Mistakes

Error-handling middleware placed before routes will never receive errors from those routes. Always put it last.
req.params.id is for URL path segments like :id. req.query.page is for query strings like ?page=2. They are not interchangeable.
Without this middleware, req.body is undefined. Every POST and PUT endpoint needs it.
A router file that does not have module.exports = router at the bottom will throw an error when imported in app.js.