How to Implement Middleware in Express.js
A step-by-step guide on how to write and use Express middleware for logging, authentication, validation, and error handling.
Understand What Middleware Is
Middleware is a function that has access to the request object, the response object, and the next function. It sits in the middle of the request-response cycle. Every incoming HTTP request passes through middleware functions in the order they are registered before reaching the final route handler. Middleware can read, modify, or end the request-response cycle.
Understand the next Function
The next function, when called without arguments, passes control to the next middleware or route handler in the stack. If you do not call next and do not send a response, the request will hang indefinitely. If you call next with an Error object as an argument, Express skips all remaining regular middleware and jumps directly to the error-handling middleware.
Write Application-Level Middleware
Use app.use to register middleware that runs for every incoming request regardless of the route. Pass the middleware function which receives req, res, and next as parameters. Always call next at the end unless you intentionally want to end the request cycle. Application-level middleware is useful for operations that apply universally like logging, CORS headers, and body parsing.
Write Route-Level Middleware
Apply middleware to specific routes by passing it as an argument between the route path and the handler function. You can pass multiple middleware functions as additional arguments and Express executes them in order. Route-level middleware is ideal for operations that apply only to certain endpoints, such as authentication checks on protected routes.
Implement a Request Logger
Write a logging middleware that records the HTTP method, the URL, the response status code, and the time taken for each request. Log the method and URL at the start of the middleware. Then override the res.send or res.json method to capture the status code after the response is sent. Call next to pass control forward and measure the elapsed time when the response finishes.
Implement a Request Validation Middleware
Write middleware that validates the shape of req.body before it reaches the controller. Check for required fields, correct data types, and valid formats like email addresses. If validation fails, call next with an error or send a 400 Bad Request response directly with a descriptive message. If validation passes, call next to allow the request to proceed to the handler.
Implement a Rate Limiting Middleware
Rate limiting protects your API from abuse by restricting how many requests a client can make in a time window. Use the express-rate-limit package to create a limiter middleware with a windowMs value defining the time window and a max value defining the maximum number of requests. Apply it globally or to specific sensitive routes like login and registration.
Implement the Global Error Handler
An Express error-handling middleware function takes exactly four parameters: err, req, res, and next. Place it at the very bottom of your middleware stack after all routes. When any middleware calls next with an error, Express skips to this handler. Log the error for debugging and send a clean, structured JSON error response to the client without leaking sensitive stack trace information.
Ready to master this completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.

