nest-best-practices
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 |
|---|---|---|
@Get('users/*') |
@Get('users/*splat') |
Wildcards must be named |
forRoutes('*') |
forRoutes('{*splat}') |
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 CacheModule now uses Keyv adapters instead of cache-manager stores:
// 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 ValidationPipe globally in main.ts — this is a security-critical step:
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:
@Column({ length: 255 }), not bare@Column() - Name tables explicitly:
@Entity('books')to avoid surprises with naming conventions - Use
@CreateDateColumn()and@UpdateDateColumn()for automatic timestamps - Use specialized validators like
@IsISBN(),@IsEmail(),@IsUUID()— not just@IsString() - Align nullability between entity and DTO: if
@Column({ nullable: true }), the DTO field should be@IsOptional()
DTO Patterns
- Import
PartialTypefrom@nestjs/swagger(not@nestjs/mapped-types) when using Swagger — this preserves API documentation metadata on partial fields - Zod validation is now an officially supported alternative to
class-validator— useZodValidationPipewithz.infer<typeof schema>for schema-first validation with type inference
Guards & Auth
NestJS v11 documents two auth approaches:
- Native JWT (recommended for simpler cases): Use
@nestjs/jwtdirectly with a customCanActivateguard that callsJwtService.verifyAsync(). No Passport dependency needed. - Passport-based (for complex strategies like OAuth2, SAML): Use
@nestjs/passportwithPassportStrategy. Now documented under "recipes" rather than primary auth docs.
Regardless of approach:
- Guard ordering matters:
@UseGuards(JwtAuthGuard, RolesGuard)— JWT guard must run first to populaterequest.userbefore RolesGuard reads it - Use
Reflector.getAllAndOverride()(not just.get()) so roles can be set at both handler and class level with handler taking precedence - RolesGuard must throw
ForbiddenExceptionwith a descriptive message when the user lacks the required role — do NOT just returnfalsefromcanActivate(). The generic 403 provides no diagnostic value. Include context:throw new ForbiddenException(\Requires roles: ${requiredRoles.join(', ')}`)` - Never hardcode JWT secrets — use
JwtModule.registerAsync()withConfigService - Define a
Roleenum rather than raw strings for type safety - In
JwtStrategy.validate()(or native guard), validate the presence of required payload fields (sub,username,roles) before returning the user object. Define aJwtPayloadinterface for type safety.
Error Messages
All thrown exceptions (ForbiddenException, UnauthorizedException, NotFoundException, 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
NestFactory.create()+app.connectMicroservice()pattern - Always call
app.enableShutdownHooks()when using Terminus health checks for graceful shutdown - Use
@nestjs/bullmq(not@nestjs/bull) — it wraps the newerbullmqlibrary. Config usesconnectionkey (notredis):BullModule.forRoot({ connection: { host: 'localhost', port: 6379 } }) - Use
BullModule.forRootAsync()withConfigServiceinjection for production config - BullMQ consumers extend
WorkerHostand implementprocess()— do NOT use the@Process()decorator (that's the older@nestjs/bullAPI) - Register
@OnWorkerEvent('completed')and@OnWorkerEvent('failed')lifecycle hooks for observability - Set
removeOnComplete: trueand configure retry withbackoff: { type: 'exponential' }on jobs - Capture and log
job.idfromqueue.add()return value for traceability - Use
job.updateProgress()for long-running jobs to enable monitoring dashboards - Define and export TypeScript interfaces for all event payloads (e.g.,
OrderCreatedEvent,UserRegisteredEvent) 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
MicroserviceHealthIndicatorfor transport checks,MemoryHealthIndicatorfor heap/RSS,DiskHealthIndicatorfor storage - Configure graceful shutdown timeout:
TerminusModule.forRoot({ gracefulShutdownTimeoutMs: 1000 })
OpenAPI / Swagger
The @nestjs/swagger CLI plugin can eliminate most manual @ApiProperty() annotations. Add to nest-cli.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 @ApiProperty() for edge cases.
Testing
@suites/unitis now a recommended testing library for NestJS:TestBed.solitary(Service).compile()— all dependencies auto-mockedTestBed.sociable(Service).expose(RealDep).compile()— selected real depsMocked<T>type for full IntelliSense on mock methods- Supports Jest, Vitest, and Sinon
- For e2e testing, use
@nestjs/testingwithTest.createTestingModule()andsupertest
Custom Decorators
- For NestJS 10+, prefer
Reflector.createDecorator<Role[]>()overSetMetadatafor custom decorators — it provides better type inference and eliminates the need for a separate metadata key constant - The
SetMetadatapattern 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 |
More from biggora/claude-plugins-registry
captcha
>
32test-web-ui
>
19tailwindcss-best-practices
Tailwind CSS v4.x utility-first CSS framework best practices. Use when styling web applications with utility classes, building responsive layouts, customizing design systems with @theme variables, migrating from v3 to v4, configuring dark mode, creating custom utilities with @utility, or working with any Tailwind CSS v4 features. This skill covers the full v4.x line through v4.2 including text shadows, masks, logical properties, and source detection. Use this skill even for simple Tailwind questions — v4 changed many class names and configuration patterns that trip people up.
18gemini-cli
>
12vite-best-practices
Vite build tool configuration, plugin API, SSR, library mode, and Vite 8 Rolldown/Oxc migration. Use when working with Vite projects, vite.config.ts, Vite plugins, building libraries or SSR apps with Vite, migrating from older Vite versions, or configuring Rolldown/Oxc options. Also use when the user mentions HMR, import.meta.glob, virtual modules, or Vite environment variables.
12test-mobile-app
>
11