The Request Lifecycle

Nest runs middleware, guards, interceptors, pipes, your handler, then interceptors and filters in a fixed order.

When a request arrives, it passes through several layers before and after your route handler. Knowing this order helps you place logic in the right layer.

NestJS request lifecycle: middleware, guard, interceptor, pipe, handler, interceptor, filterMiddlewareGuardInterceptor(before)PipeHandlerInterceptor(after)Exception Filter(on error)Response
The order Nest runs each layer on the way in, and again (interceptor, filter) on the way out.

The order

  1. Middleware - runs first, before the route is known.
  2. Guards - decide whether the request may proceed (auth).
  3. Interceptors (before) - wrap the handler; run pre-logic.
  4. Pipes - validate and transform inputs.
  5. Route handler - your controller method.
  6. Interceptors (after) - transform the response.
  7. Exception filters - catch any error thrown along the way.

Example

Example Β· typescript
// Each layer is opt-in and composable:
// @UseGuards(AuthGuard)        -> guards
// @UseInterceptors(LogInterceptor) -> interceptors
// @UsePipes(ValidationPipe)    -> pipes
// @UseFilters(HttpExceptionFilter) -> filters

@UseGuards(AuthGuard)
@Get('secret')
getSecret() {
  return 'protected data';
}

When to use it

  • A developer debugging an unexpected 403 traces the request through the lifecycle to discover a guard is rejecting it before the controller runs.
  • An architect documents that CORS middleware runs first, then authentication guards, then the validation pipe, so the team knows exactly where to add each concern.
  • A team adds request-ID middleware early in the chain so the ID is available to all subsequent lifecycle stages including exception filters.

More examples

Lifecycle order overview

Documents the fixed seven-step request lifecycle so developers know exactly where to place each cross-cutting concern.

Example Β· ts
// Inbound order:
// 1. Middleware        (app.use / @Module middleware)
// 2. Guards           (@UseGuards)
// 3. Interceptors     (@UseInterceptors β€” before)
// 4. Pipes            (@UsePipes / param decorators)
// 5. Route Handler
// Outbound order:
// 6. Interceptors     (after β€” response transform)
// 7. Exception Filter (if an error was thrown)

Applying multiple concerns at once

Shows controller-level decorators stacked in lifecycle order so the intent is self-documenting.

Example Β· ts
import { Controller, Get, UseGuards, UseInterceptors, UsePipes } from '@nestjs/common';

@Controller('orders')
@UseGuards(JwtAuthGuard)          // step 2
@UseInterceptors(LoggingInterceptor) // step 3 & 6
@UsePipes(ValidationPipe)          // step 4
export class OrdersController {
  @Get() findAll() { return []; }
}

Exception bubbles to filter

Illustrates that throwing inside a handler skips the remaining lifecycle and transfers control to the nearest exception filter.

Example Β· ts
// If handler throws, execution jumps to ExceptionFilter
@Get(':id')
findOne(@Param('id') id: string) {
  const order = this.ordersService.findOne(+id);
  if (!order) {
    throw new NotFoundException(`Order ${id} not found`);
    // β†’ caught by HttpExceptionFilter
  }
  return order;
}

Discussion

  • Be the first to comment on this lesson.