Middleware Fundamentals
By Syncfusion®, Inc. · Last updated
What middleware is, the (req, res, next) pipeline, the three ways to finish, middleware types, global, path-based and route-specific mounting, registration order, custom middleware, access-control middleware, factories and async middleware in Express 5.
What you will learn
- Explain how the middleware pipeline runs
- Finish middleware with next, a response or next(err)
- Mount middleware globally, on a path or on a route
- Write custom and configurable middleware
- Handle errors from async middleware in Express 5
Middleware Introduction
Middleware = a function that runs on a request before (or instead of) your route.
- It has three inputs:
(req, res, next). - next = a function that passes the request to the next step.
- Middleware can read
req, changereqandres, or send an answer. - Express runs middleware in the order you add it.
- Logging, body parsing, login checks and error pages are all middleware.
Simple lesson: Middleware is a checkpoint every request walks through.
A Real-World Example
Think about the school morning line.
- The gate guard checks your ID card.
- The class teacher marks attendance.
- The monitor checks your uniform.
- Then you reach your classroom.
Any checkpoint can stop you: "No ID card, go home". Each checkpoint is middleware. The classroom is your route.
In this lesson, you will learn:
- The shape of a middleware function.
- The three ways middleware can finish.
- Middleware types and where to mount them.
- Why order matters.
- How to write custom and reusable middleware.
- How async middleware handles errors in Express 5.
The Middleware Pipeline
Animation: a request passes a logger, a login check and a route; a second request is stopped at the login check with 401
logger
requireLogin
GET /orders
200 OK
401 Unauthorized
next() next() res.send res.status(401)
Blue request: every step calls next(). Orange request: the login check answers and the trip ends.
Request-response pipeline = the line of middleware and routes a request passes through.
- Each step either passes the request on or ends the trip.
- The order of steps is the order of your
app.usecalls. - Routes are the last stop in the line.
Simple lesson: Requests flow down the pipeline until something answers.
Three Ways to Finish
Every middleware must do one of these three things:
- Call next() = "I am done, pass it on".
- Send a response = "I answered, stop here". Use
returnso nothing else runs. - Call next(error) = "Something broke". Express jumps to error middleware.
- If it does none of these, the request hangs. The client waits forever.
- The first request has the header, so it passes to the route.
- The second gets 401 from the middleware. The route never runs.
/brokenreaches the error handler and gets 500./stucknever gets an answer.
A hanging request is hard to spot, because nothing crashes. If a client spins forever, look for middleware that forgot next().
Simple lesson: Call next(), send a response, or pass an error. Never nothing.
Middleware Types
- Application-level:
app.use(fn)orapp.get(path, fn, handler). - Router-level:
router.use(fn). See Routing and Routers. - Built-in: comes with Express, such as
express.json()andexpress.static(). - Third-party: installed with npm, such as
helmet,corsandmorgan. - Error-handling: has four inputs:
(err, req, res, next).
Simple lesson: Same idea everywhere. Only the place you mount it changes.
Mounting Middleware
- Global:
app.use(fn)runs for every request. - Path-based:
app.use("/admin", fn)runs for/adminand everything under it. - Route-specific:
app.get("/orders", fn, handler)runs for that one route. - Many at once:
app.use(fnA, fnB)orapp.get(path, [fnA, fnB], handler). - Middleware stack = all the middleware in order, for one path.
- Watch the terminal for each request.
[global]prints every time. The others print only on their paths.
Simple lesson: Mount middleware as narrowly as the job needs.
Middleware Order
- Express runs middleware in registration order: the order of your code.
- Register middleware before the routes that need it.
express.json()after a route means that route sees no body.- Register error middleware after all routes.
- The answer says
"nothing", because the body was never parsed. - Move
app.use(express.json())above the route and run again.
Easy way to remember: helpers on top, routes in the middle, errors at the bottom.
Simple lesson: Middleware only helps the routes that come after it.
Writing Custom Middleware
Middleware is just a function. Some common jobs:
- Header check: reject requests without an API key.
- Feature flag: turn a route off with one setting.
- Request property: add
req.requestTimefor later use. - Response header: add
X-Canteento every answer. - Normalise data: trim spaces from
req.query.search. - Response locals: put the user in
res.locals.user.
Put each one in its own file in a middleware/ folder, and export it.
searchForis"dosa", without the extra spaces.- Every answer carries
X-Canteen. Check Headers.
Simple lesson: Small middleware files, each with one job.
Access-Control Middleware
A common job: only let some users through.
- Read the user's role, for example from a header or the session.
- Compare it with the role the route needs.
- Allowed: call
next(). - Not logged in at all: answer 401.
- Logged in but not allowed: answer 403.
Middleware Factories
Middleware factory = a function that returns middleware.
requireRole("staff")returns a checker for staff.requireRole("admin")returns a checker for admins.- One function, many configured checkers.
A header like X-Role is easy to fake. This lab uses it only to show the idea. Real apps read the role from a login session. See Cookies and Sessions.
Simple lesson: A factory turns one checker into many configured checkers.
Async Middleware
Middleware can be async when it waits for something, like a database.
- In Express 5, if an
asyncfunction throws, Express catches it. - The error goes to error middleware, just like
next(err). - In Express 4, you had to wrap it in
try/catchyourself. - Errors in callbacks and timers are still not caught. Use
next(err)there.
/menu/9throws inside anasyncfunction.- Express 5 sends the error to the four-input middleware for you.
Simple lesson: In Express 5, throwing in async middleware is safe. Errors reach your error handler.
Common mistakes
| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
Forgetting next() | Express moves on by itself | You must call next() or respond | The request hangs |
res.send then next() | Both can happen | Answer or pass on, not both | ERR_HTTP_HEADERS_SENT |
| Parser after the routes | Order does not matter | Middleware helps only later routes | req.body is undefined |
| Error middleware with 3 inputs | Any middleware can catch errors | It needs exactly 4 inputs | Errors skip it |
| Error middleware at the top | Put important things first | It must come after routes | It never sees route errors |
| Trusting a role header | Clients send honest headers | Read roles from the session | Anyone becomes admin |
Check Yourself
Exercises
What to Remember
- Middleware is
(req, res, next), running in registration order. - Finish with
next(), a response, ornext(err). Never nothing. - Mount it globally, on a path, on a router or on one route.
- Helpers on top, routes in the middle, error middleware at the bottom.
- Factories like
requireRole("staff")make configurable middleware. - Express 5 sends errors from
asyncmiddleware to your error handler.
Next: Body Parsers and Third-Party Middleware. You will read JSON, forms and text from request bodies, and add packages from npm.