Request Lifecycle

What is the order of the request lifecycle in NestJS?

Incoming request → middleware → guards → interceptors (before) → pipes → controller handler (→ service) → interceptors (after, on the response stream) → response. Any exception thrown along the way goes to exception filters.

Within each kind, global ones run first, then controller-level, then method-level (filters resolve from the most specific outward).

Middleware vs guard: when do you use which?

Middleware runs before routing decisions are exposed to you and does not know which handler will run; it is Express-style (req, res, next) and fits logging, request ids, body parsing, helmet. A guard gets an ExecutionContext with the target class and handler, so it can read metadata like @Roles() or @Public(); it fits authentication and authorization. Guards return true/false (false = 403) or throw.

What can an interceptor do that a guard or pipe cannot?

An interceptor wraps the handler: it runs code before and after it and works with the response as an RxJS stream. It can transform the result (map), log timing (tap), add a timeout, map errors (catchError), or skip the handler completely and return a cached value. Guards only allow/deny; pipes only see one argument.

How would you return the same error format for every error in the app?

Write a global exception filter with @Catch() (catches everything), register it with { provide: APP_FILTER, useClass: AllExceptionsFilter }, and in catch(exception, host) build one shape: status from HttpException.getStatus() or 500, a stable code, a message, path and request id. Log 5xx with stack traces but do not send internals to the client. Optionally add specific filters for Prisma/TypeORM errors (P2002 → 409).

Why prefer APP_GUARD/APP_PIPE providers over app.useGlobalGuards()?

app.useGlobalGuards(new X()) creates the object outside the DI container, so it cannot inject services (Reflector, ConfigService, repositories), and it is not applied in e2e tests that build the app from AppModule unless you repeat the call. Registering { provide: APP_GUARD, useClass: X } in a module lets Nest construct it with DI and keeps it part of the module graph.