Quick Reference
| Topic | File |
|---|---|
| Module system, circular deps, dynamic modules | modules.md |
| DI, providers, injection scopes, custom providers | dependency-injection.md |
| Controllers, routing, request lifecycle | controllers.md |
| Guards, pipes, interceptors, middleware, filters | lifecycle.md |
| DTOs, validation, transformation | validation.md |
| Database integration (TypeORM, Prisma, Mongoose) | database.md |
| Testing: unit, integration, e2e | testing.md |
| Microservices, queues, events, WebSockets | microservices.md |
| Config, environment, secrets management | config.md |
| Performance, caching, serialization | performance.md |
NestJS vs Plain Node.js — Key Differences
NestJS builds on Node.js/Express (or Fastify) but introduces an opinionated architecture. The main things that catch people:
- Everything is a class with decorators —
@Module,@Controller,@Injectableare not optional annotations, they drive the DI container and module graph. - Module boundaries matter — a provider is NOT globally available unless explicitly exported and imported. This is the #1 source of "Nest can't resolve dependency" errors.
- Request lifecycle is layered — Middleware → Guards → Interceptors (before) → Pipes → Handler → Interceptors (after) → Exception Filters. Order matters and each layer has a distinct job.
- TypeScript is assumed — decorators, metadata reflection (
reflect-metadata), andemitDecoratorMetadataare load-bearing. Misconfiguredtsconfig.jsonbreaks DI silently.
Critical Traps
@Injectable()missing — class won't be in DI container, cryptic "resolve dependency" error- Provider not in module's
providersarray — same error, different cause - Provider not
exportsed — importing module can't see it, even though the module is imported - Circular module dependency — use
forwardRef(() => ModuleClass)on BOTH sides - Circular provider injection — use
forwardRef(() => ServiceClass)+@Inject(forwardRef(...)) @Body()empty — missingContent-Type: application/jsonheader or body-parser not configured- Validation not firing — forgot
app.useGlobalPipes(new ValidationPipe())or missingclass-transformer - Guard returning
falsesilently → 403 — no error message by default, must throw specific exception @Res()used → Nest loses response control — use@Res({ passthrough: true })or avoid@Res()- Exception filter not catching — filter bound to wrong scope (method vs controller vs global)
onModuleInit/onModuleDestroy— lifecycle hooks only fire if class is@Injectable()AND in providersConfigService.get()returnsundefined— env var not in.envorConfigModulenot imported in that module- Fastify adapter — Express middleware won't work, must use Fastify equivalents