NestJS is a progressive Node.js framework for building efficient and scalable server-side applications. It uses TypeScript by default, supports both Express and Fastify, and provides an out-of-the-box application architecture inspired by Angular. NestJS combines elements of OOP, FP, and FRP, making it ideal for building enterprise-grade applications.
Skill based on NestJS documentation, updated 2026-03-28. Covers NestJS v11 with Express v5.
How to Use This Skill
When generating NestJS code, read the relevant reference files below for the specific topic. The references contain current API patterns, correct import paths, and production-ready examples.
Always apply the production best practices below — these are patterns that matter in production and are easy to miss without explicit guidance.
NestJS v11 Breaking Changes
Be aware of these when generating code for NestJS v11+:
Node.js v20+ Required
Node.js v16 and v18 are no longer supported. Always target Node.js v20+.
Express v5 Route Matching
NestJS v11 uses Express v5 by default. Route patterns have changed:
| Express v4 (Old) | Express v5 (New) | Notes |
|---|
| | Wildcards must be named |
| | Braces make path optional (matches root) |
| optional character | Not supported | Use braces instead |
| Regex in routes | Not supported | Regex characters no longer work |
CacheModule Migration to Keyv
The
now uses Keyv adapters instead of
stores:
typescript
// OLD (pre-v11) — no longer works
CacheModule.register({ store: redisStore, host: 'localhost', port: 6379 });
// NEW (v11+) — uses @keyv/redis
import { KeyvRedis } from '@keyv/redis';
CacheModule.registerAsync({
useFactory: async () => ({
stores: [new KeyvRedis('redis://localhost:6379')],
}),
});
Production Best Practices
Bootstrap & Application Setup
Configure
globally in
— this is a security-critical step:
typescript
app.useGlobalPipes(new ValidationPipe({
whitelist: true, // strips unknown properties
forbidNonWhitelisted: true, // rejects requests with unknown properties (400)
transform: true, // enables automatic type coercion for params
}));
Entity & Schema Discipline
- Use explicit column lengths: , not bare
- Name tables explicitly: to avoid surprises with naming conventions
- Use and for automatic timestamps
- Use specialized validators like , , — not just
- Align nullability between entity and DTO: if
@Column({ nullable: true })
, the DTO field should be
DTO Patterns
- Import from (not ) when using Swagger — this preserves API documentation metadata on partial fields
- Zod validation is now an officially supported alternative to — use with for schema-first validation with type inference
Guards & Auth
NestJS v11 documents two auth approaches:
- Native JWT (recommended for simpler cases): Use directly with a custom guard that calls . No Passport dependency needed.
- Passport-based (for complex strategies like OAuth2, SAML): Use with . Now documented under "recipes" rather than primary auth docs.
Regardless of approach:
- Guard ordering matters:
@UseGuards(JwtAuthGuard, RolesGuard)
— JWT guard must run first to populate before RolesGuard reads it
- Use
Reflector.getAllAndOverride()
(not just ) so roles can be set at both handler and class level with handler taking precedence
- RolesGuard must throw with a descriptive message when the user lacks the required role — do NOT just return from . The generic 403 provides no diagnostic value. Include context:
throw new ForbiddenException(\
Requires roles: ${requiredRoles.join(', ')}`)`
- Never hardcode JWT secrets — use
JwtModule.registerAsync()
with
- Define a enum rather than raw strings for type safety
- In (or native guard), validate the presence of required payload fields (, , ) before returning the user object. Define a interface for type safety.
Error Messages
All thrown exceptions (
,
,
, etc.) should include descriptive messages that identify what was expected, what was found, and what action the consumer should take. Do not rely on framework default messages in production code.
Microservices & Queues
- For hybrid apps (HTTP + microservice), use +
app.connectMicroservice()
pattern
- Always call
app.enableShutdownHooks()
when using Terminus health checks for graceful shutdown
- Use (not ) — it wraps the newer library. Config uses key (not ):
typescript
BullModule.forRoot({ connection: { host: 'localhost', port: 6379 } })
- Use
BullModule.forRootAsync()
with injection for production config
- BullMQ consumers extend and implement — do NOT use the decorator (that's the older API)
- Register
@OnWorkerEvent('completed')
and lifecycle hooks for observability
- Set and configure retry with
backoff: { type: 'exponential' }
on jobs
- Capture and log from return value for traceability
- Use for long-running jobs to enable monitoring dashboards
- Define and export TypeScript interfaces for all event payloads (e.g., , ) for type safety across service boundaries
Health Checks
- Don't just check one thing — include multiple indicators: service connectivity (Redis/DB), memory (heap + RSS), and disk usage
- Use
MicroserviceHealthIndicator
for transport checks, for heap/RSS, for storage
- Configure graceful shutdown timeout:
TerminusModule.forRoot({ gracefulShutdownTimeoutMs: 1000 })
OpenAPI / Swagger
The
CLI plugin can eliminate most manual
annotations. Add to
:
json
{
"compilerOptions": {
"plugins": [{
"name": "@nestjs/swagger",
"options": { "classValidatorShim": true, "introspectComments": true }
}]
}
}
With the plugin enabled, TypeScript types, default values, optional markers, and JSDoc comments are automatically inferred — you only need explicit
for edge cases.
Testing
- is now a recommended testing library for NestJS:
TestBed.solitary(Service).compile()
— all dependencies auto-mocked
TestBed.sociable(Service).expose(RealDep).compile()
— selected real deps
- type for full IntelliSense on mock methods
- Supports Jest, Vitest, and Sinon
- For e2e testing, use with
Test.createTestingModule()
and
Custom Decorators
- For NestJS 10+, prefer
Reflector.createDecorator<Role[]>()
over for custom decorators — it provides better type inference and eliminates the need for a separate metadata key constant
- The pattern still works and is fine for simple cases
CLI
| Topic | Description | Reference |
|---|
| CLI Overview | Scaffolding, building, and running applications | cli-overview |
| Monorepo & Libraries | Workspaces, apps, shared libraries | cli-monorepo |
Core References
| Topic | Description | Reference |
|---|
| Controllers | Route handlers, HTTP methods, request/response handling | core-controllers |
| Modules | Application structure, feature modules, shared modules, dynamic modules | core-modules |
| Providers | Services, dependency injection, custom providers | core-providers |
| Dependency Injection | DI fundamentals, custom providers, scopes | core-dependency-injection |
| Middleware | Request/response middleware, functional middleware | core-middleware |
Fundamentals
| Topic | Description | Reference |
|---|
| Pipes | Data transformation and validation pipes | fundamentals-pipes |
| Guards | Authorization guards, role-based access control | fundamentals-guards |
| Interceptors | Aspect-oriented programming, response transformation | fundamentals-interceptors |
| Exception Filters | Error handling, custom exception filters | fundamentals-exception-filters |
| Custom Decorators | Creating custom parameter decorators | fundamentals-custom-decorators |
| Dynamic Modules | Configurable modules, module configuration | fundamentals-dynamic-modules |
| Execution Context | Accessing request context, metadata reflection | fundamentals-execution-context |
| Provider Scopes | Singleton, request-scoped, transient providers | fundamentals-provider-scopes |
| Lifecycle Events | Application and provider lifecycle hooks | fundamentals-lifecycle-events |
| Lazy Loading | Loading modules on-demand for serverless | fundamentals-lazy-loading |
| Circular Dependency | Resolving circular dependencies with forwardRef | fundamentals-circular-dependency |
| Module Reference | Accessing providers dynamically with ModuleRef | fundamentals-module-reference |
| Testing | Unit testing and e2e testing with @nestjs/testing | fundamentals-testing |
Techniques
| Topic | Description | Reference |
|---|
| Validation | ValidationPipe, class-validator, Zod validation | techniques-validation |
| Configuration | Environment variables, ConfigModule, configuration management | techniques-configuration |
| Database | TypeORM, Prisma, MongoDB integration | techniques-database |
| Caching | Keyv-based cache manager, Redis integration | techniques-caching |
| Logging | Built-in logger, custom loggers, JSON logging | techniques-logging |
| File Upload | File upload handling with multer, validation | techniques-file-upload |
| Versioning | URI, header, and media type API versioning | techniques-versioning |
| Serialization | Response serialization with class-transformer | techniques-serialization |
| Queues | Background job processing with BullMQ | techniques-queues |
| Task Scheduling | Cron jobs, intervals, and timeouts | techniques-task-scheduling |
| Events | Event-driven architecture with EventEmitter | techniques-events |
| HTTP Module | Making HTTP requests with Axios | techniques-http-module |
| Fastify | Using Fastify for better performance | techniques-fastify |
| Sessions & Cookies | HTTP sessions and cookies for stateful apps | techniques-sessions-cookies |
| Streaming & SSE | Compression, file streaming, Server-Sent Events | techniques-compression-streaming-sse |
| MVC & Serve Static | Template rendering (Handlebars) and SPA static serving | techniques-mvc-serve-static |
Security
| Topic | Description | Reference |
|---|
| Authentication | Native JWT auth and Passport integration | recipes-authentication |
| Authorization | RBAC, claims-based, CASL integration | security-authorization |
| CORS & Rate Limiting | CORS, Helmet, ThrottlerModule | security-cors-helmet-rate-limiting |
| Encryption & Hashing | bcrypt, argon2, password hashing | security-encryption-hashing |
OpenAPI
| Topic | Description | Reference |
|---|
| Swagger | OpenAPI documentation generation, CLI plugin | openapi-swagger |
WebSockets
| Topic | Description | Reference |
|---|
| Gateways | Real-time communication with Socket.IO/ws | websockets-gateways |
| Guards & Exception Filters | WsException, BaseWsExceptionFilter, interceptors, pipes | websockets-advanced |
Microservices
| Topic | Description | Reference |
|---|
| Overview | Transport layers, message patterns, events | microservices-overview |
| gRPC | Protocol Buffers, streaming, metadata, reflection | microservices-grpc |
| Transports | Redis, Kafka, NATS, RabbitMQ configuration | microservices-transports |
GraphQL
| Topic | Description | Reference |
|---|
| Overview | Code-first and schema-first approaches | graphql-overview |
| Resolvers & Mutations | Queries, mutations, field resolvers | graphql-resolvers-mutations |
| Subscriptions | Real-time subscriptions with PubSub | graphql-subscriptions |
| Scalars, Unions & Enums | Interfaces, scalars, union types, enums | graphql-scalars-unions-enums |
Recipes
| Topic | Description | Reference |
|---|
| CRUD Generator | Nest CLI resource generator | recipes-crud-generator |
| Documentation | OpenAPI/Swagger integration | recipes-documentation |
| TypeORM | TypeORM integration and usage | recipes-typeorm |
| Prisma | Prisma ORM integration | recipes-prisma |
| Mongoose | MongoDB with Mongoose ODM | recipes-mongoose |
| CQRS | Command Query Responsibility Segregation | recipes-cqrs |
| Terminus | Health checks and readiness/liveness probes | recipes-terminus |
FAQ
| Topic | Description | Reference |
|---|
| Raw Body & Hybrid | Webhook signature verification, HTTP + microservices | faq-raw-body-hybrid |
Best Practices
| Topic | Description | Reference |
|---|
| Request Lifecycle | Understanding execution order and flow | best-practices-request-lifecycle |