Tutorials Logic, IN info@tutorialslogic.com

Express.js Routing and Middleware: Understand The Request Pipeline

Ordered Request Pipeline

Routing decides which code should handle a request. Middleware decides what happens to that request on the way there.

This is the core of Express. If you understand the middleware pipeline well, many other backend concepts start feeling less mysterious.

Beginners need to learn the visible flow. Professionals need to design that flow so auth, logging, validation, and error handling stay orderly.

A surprising number of Express bugs come from middleware order, hidden side effects, or route matching assumptions.

What Middleware Really Means

Middleware is easiest to understand as shared processing that sits between the raw request and the final handler. It can inspect the request, reject it, enrich it, log it, or pass it onward.

Once you see middleware as a pipeline, Express becomes much easier to reason about. You stop thinking in isolated route functions and start thinking in stages of processing.

  • Some middleware is global.
  • Some middleware belongs only to certain routes.
  • Each middleware function should do one clear job well.

Why Order Changes Everything

Express runs middleware in the order you register it. That means the exact placement of body parsing, auth checks, route registration, logging, and error handlers changes behavior. This is one of the first places where backend code stops feeling like ordinary sequential JavaScript and starts feeling like request orchestration.

Many beginners discover this through bugs: a route cannot read the request body, a protected route runs before auth middleware, or an error handler never sees the thrown error because the control flow is wrong.

  • Put general parsing and logging early.
  • Put protection middleware before the routes that need protection.
  • Put error handling after the normal route and middleware chain.

Follow The Express Middleware Pipeline

Express processes matching middleware and handlers in registration order. Application middleware can add request IDs, security headers, parsers, and logging. Routers group feature routes. Route-level middleware performs authentication, authorization, or validation before the final controller.

A middleware function must send a response, call next(), or pass an error to next(error). Calling neither leaves the request waiting. Calling next after a response may cause another handler to write again. Async middleware should forward rejected promises according to the Express version and project wrapper strategy.

Order matters. Parse JSON before validating the body, authenticate before authorization, and register the final not-found handler after all routes. Error middleware comes last and uses the four-argument signature. Keep middleware narrow so the request path remains explainable.

  • Register middleware in execution order.
  • Ensure every path responds or calls next.
  • Parse before validating request bodies.
  • Authenticate before checking permissions.
  • Place not-found and error handlers last.

How Teams Keep Pipelines Understandable

In a larger service, middleware can quietly become a maze. Professionals keep it understandable by naming middleware clearly, limiting hidden mutation of the request object, and documenting shared route stacks.

A good request pipeline is not only functional. It is explainable. If a teammate cannot describe why a request was rejected or transformed, the pipeline is already too opaque.

  • Avoid middleware that mutates too many unrelated fields.
  • Prefer narrow reusable middleware over giant all-purpose functions.
  • Review route stacks the way you review business logic.

Prove Middleware Order with a Protected Route

Create public and protected routers, mount authentication before protected handlers, and place the error middleware last. Test the same endpoint with no token, an invalid token, and a valid token.

Mounting validation before parsing JSON produces missing fields, while mounting authorization after the handler exposes protected behavior. Error middleware with the wrong four-argument signature is ignored by Express.

Verification must use evidence that matches the concept. Assert which middleware ran for each case, the returned status, and that the protected handler never runs for rejected requests. Repeat the check after deliberately introducing the failure, then after the fix. The contrast between those runs is the part that turns a definition into practical understanding.

Trust Boundaries, Async Context, And Pipeline Performance

Configure proxy trust correctly before using forwarded IP or protocol headers. An overly broad trust setting lets clients spoof network identity, while no trust behind a real proxy breaks secure-cookie and address behavior. Normalize request IDs at the trusted edge and replace untrusted client copies.

Use AsyncLocalStorage or an equivalent context mechanism carefully for request-scoped logging and tracing. Do not use mutable globals. Bound body sizes and parser work before expensive authentication or application logic, and apply route-specific limits when upload and JSON endpoints have different risks.

Measure middleware latency and failure rates. Avoid synchronous CPU-heavy work and repeated database lookups in global middleware. Cache safe identity metadata briefly when appropriate, but re-check sensitive account state and resource permission at the operation boundary.

  • Configure trusted proxies from deployment topology.
  • Propagate request context without mutable globals.
  • Limit body size before expensive processing.
  • Measure latency contributed by middleware.
  • Keep resource authorization close to the resource.

Pipeline Control

A middleware must end the response, call next(), or return a promise whose completion Express can observe. Calling next and then sending a response later creates double-send races; forgetting both leaves the request hanging. Return immediately after sending or forwarding an error so subsequent code cannot mutate state or write another response.

Mount parsers only where their content types and size limits are expected. express.json populates req.body after a matching JSON request reaches it; routes mounted before the parser see no parsed body. A webhook that verifies a signature over raw bytes may need a route-specific raw parser before ordinary JSON parsing. One global permissive parser makes those boundaries harder to reason about.

Keep the 404 handler after all mounted routers and the error handler after the 404 path. A missing route is not automatically an exception, while a rejected async handler is. Test both so an API never returns an HTML fallback page or hangs because control reached the end of an incomplete pipeline.

Route and Router Skips

next('route') skips the remaining callbacks for the current route and continues route matching; next('router') exits the current router. Any other value passed to next enters error handling. Use these controls sparingly and test order explicitly, because a new earlier middleware can change which authentication, binding, or rate-limit checks run.

Proxy Trust Test

Configure trust proxy from the exact reverse-proxy topology, then test direct and proxied requests. Verify req.ip, req.ips, req.protocol, secure-cookie behavior, and rate-limit keys. A broad true setting can trust attacker-supplied forwarded headers when the app is reachable without the expected proxy; a disabled setting behind TLS termination can make secure requests appear HTTP.

A typical protected request path

This is a realistic example of how several pieces cooperate before the handler responds.

A typical protected request path
Request -> logger -> JSON parser -> auth middleware -> role check -> route handler -> response -> error handler if something fails
  • Each stage should have a clear job.
  • If order changes, the behavior may also change.
  • The route handler should not re-do work that middleware already handled.

Prove Middleware Order with a Protected Route example

Prove Middleware Order with a Protected Route example
router.post('/orders',
  authenticate,
  validate(createOrderSchema),
  createOrder
);
app.use(errorHandler);

Ordered Express application pipeline

This sequence separates global transport concerns from feature rules.

Ordered Express application pipeline
app.set("trust proxy", 1);
app.use(requestId());
app.use(securityHeaders());
app.use(express.json({ limit: "100kb" }));
app.use(requestLogger());

app.use("/orders", ordersRouter);

app.use(notFoundHandler);
app.use(errorHandler);
  • Adjust proxy trust to the actual infrastructure.
  • Use smaller limits for ordinary JSON APIs.
  • Error middleware must remain after routes.

Protected route middleware chain

Each stage has one observable responsibility.

Protected route middleware chain
router.post("/",
  authenticate,
  authorize("orders:create"),
  validate(createOrderSchema),
  createOrderController
);
  • Rejected requests must not reach later handlers.
  • Validation should expose a trusted parsed value.
  • Test missing, invalid, forbidden, and successful cases.
Before you move on

Express.js Routing and Middleware: Understand The Request Pipeline Mastery Check

1 checks
  • The difference between general middleware and route-specific middleware.

Express.js Questions Learners Ask

Yes. That is one of its most important jobs for validation, authentication, rate limiting, and other gatekeeping behavior.

No. Middleware is best for cross-cutting request concerns. Core business logic usually belongs elsewhere.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.