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.
The order
- Middleware - runs first, before the route is known.
- Guards - decide whether the request may proceed (auth).
- Interceptors (before) - wrap the handler; run pre-logic.
- Pipes - validate and transform inputs.
- Route handler - your controller method.
- Interceptors (after) - transform the response.
- Exception filters - catch any error thrown along the way.
Example
// 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.
// 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.
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.
// 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