CalcSnippets Search
Node.js 3 min read

Express.js Middleware Explained With Practical Backend Examples

Learn Express middleware for routing, authentication, errors, logging, validation, security headers, async handling, and maintainable Node.js APIs.

Middleware is the pipeline around each request

Express.js middleware functions run during the request-response lifecycle. They can read the request, modify it, end the response, or pass control to the next function. This makes middleware useful for logging, authentication, parsing JSON, validating input, adding security headers, serving static files, handling errors, and attaching request-specific context.

The concept is simple, but order matters. Middleware runs in the order it is registered. A route that expects req.user needs authentication middleware before it. Error handling middleware must have the right signature and usually appears after routes. A body parser must run before code that reads the parsed body.

Keep middleware focused

A good middleware has one clear job. It checks authentication, adds a request ID, validates a content type, logs timing, or handles errors. Problems appear when middleware performs broad business workflows, makes slow external calls on every request, or silently changes behavior for routes that did not expect it.

Authentication middleware should identify the caller. Authorization should still check whether that caller can access the specific resource. Mixing those responsibilities can lead to APIs that verify a token but forget object-level permissions.

  • Register middleware in a deliberate order.
  • Keep request-wide behavior separate from route-specific business logic.
  • Use async error handling patterns so rejected promises do not disappear.
  • Test middleware for success, failure, and bypass cases.

Error middleware shapes developer experience

A consistent error handler makes APIs easier to consume and operate. It can convert known application errors into stable status codes and response bodies while hiding internal stack traces from public clients. It can also log request IDs, user IDs, route names, and safe error details for investigation.

Do not return every error as 500. Validation errors, authentication failures, permission denials, conflicts, rate limits, and missing resources should be classified clearly. Clients and monitoring systems depend on that classification.

Middleware should be observable and cheap

Because middleware runs often, performance costs multiply. Avoid expensive database calls in global middleware unless they are required for every route. If middleware adds timing or tracing, make sure the data appears in logs or metrics. Invisible work is hard to debug.

Express middleware is powerful because it gives the application a clear request pipeline. Use that power to make cross-cutting behavior consistent, not to hide product logic where future developers will struggle to find it.

Test middleware in isolation and in routes

A middleware can pass isolated tests but still behave badly when combined with body parsing, authentication, routers, and error handlers. Test important middleware directly, then test at least one realistic route path. This catches ordering mistakes and assumptions about request state before they reach production.

Keep global middleware conservative

Global middleware affects every route, including health checks, webhooks, static assets, and admin tools. Before adding work globally, ask whether every request truly needs it. Route-level middleware or router-specific middleware is often safer when behavior applies only to one product area.

Keep reading

Related guides