Skip to main content
Practice Problems

What is middleware in NestJS and how does it differ from guards?

Middleware in NestJS

Middleware in NestJS is identical to Express middleware β€” a function that runs before the route handler and has access to req, res, and next. However, NestJS wraps it in a class-based format that supports dependency injection.


Creating Middleware

typescript
import { Injectable, NestMiddleware } from '@nestjs/common'; import { Request, Response, NextFunction } from 'express'; @Injectable() export class LoggerMiddleware implements NestMiddleware { use(req: Request, res: Response, next: NextFunction) { console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`); next(); } }

Functional Middleware (Simple)

typescript
// No class needed β€” just a function export function loggerMiddleware(req: Request, res: Response, next: NextFunction) { console.log(`${req.method} ${req.url}`); next(); }

Registering Middleware

Unlike Guards, Pipes, and Interceptors, NestJS middleware is registered in the module using the configure() method:

typescript
import { Module, NestModule, MiddlewareConsumer, RequestMethod } from '@nestjs/common'; @Module({ controllers: [UsersController, ProductsController], }) export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer .apply(LoggerMiddleware) .forRoutes('*'); // all routes consumer .apply(AuthMiddleware) .exclude( { path: 'auth/login', method: RequestMethod.POST }, { path: 'auth/register', method: RequestMethod.POST }, ) .forRoutes(UsersController); // all UsersController routes consumer .apply(RateLimitMiddleware) .forRoutes({ path: 'api/*', method: RequestMethod.ALL }); // Multiple middleware in order consumer .apply(CorsMiddleware, HelmetMiddleware, LoggerMiddleware) .forRoutes('*'); } }

Practical Example: Request ID Middleware

typescript
import { v4 as uuid } from 'uuid'; @Injectable() export class RequestIdMiddleware implements NestMiddleware { use(req: Request, res: Response, next: NextFunction) { const requestId = req.headers['x-request-id'] as string || uuid(); req['requestId'] = requestId; res.setHeader('x-request-id', requestId); next(); } }

Middleware vs Guards vs Interceptors

FeatureMiddlewareGuardInterceptor
Access to ExecutionContextβŒβœ…βœ…
Access to metadata (Reflector)βŒβœ…βœ…
Runs before guardsβœ…β€”β€”
DI supportβœ…βœ…βœ…
Can abort requestβœ…βœ…βœ…
Can modify responseβœ…βŒβœ…
PurposeLogging, CORS, body parseAuth, rolesTransform, cache, timing

Execution Order

Request β†’ Middleware (in order registered) β†’ Guards β†’ Interceptors (before) β†’ Pipes β†’ Handler β†’ Interceptors (after) β†’ Response

Middleware runs before guards and has no access to NestJS metadata β€” use guards for auth/authorization, middleware for lower-level concerns (logging, CORS, request parsing).


Summary

NestJS Middleware works like Express middleware but with class syntax and DI support. Register it via configure() in the module. Use middleware for infrastructure concerns (logging, request IDs, rate limiting with Express packages). Use Guards for authentication/authorization β€” they have access to route metadata and the full ExecutionContext.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?
Practice Problems