nestjs-best-practices · ejirocodes — Claude Code skill: NestJS 11 rules
A skill that feeds your agent NestJS 11 practices for TypeScript apps: how to shape modules, controllers and services, and which mistakes to flag in review.
npx skills add ejirocodes/agent-skills --skill nestjs-best-practices -a claude-codeWhat nestjs-best-practices does
The skill activates while you write, review or refactor NestJS code: modules, controllers, providers, dependency injection, @Injectable, @Controller, @Module, middleware, guards, interceptors, pipes, exception filters, DTOs, JWT auth, Passport strategies, TypeORM, Prisma, Drizzle, GraphQL resolvers, microservices over TCP, Redis, NATS and Kafka, and tests.
It ships reference files per topic: core architecture, request lifecycle, validation and pipes, authentication, database integration, testing, OpenAPI and GraphQL, microservices. There is also a list of common mistakes — skipping forwardRef() on circular dependencies, throwing a plain error instead of HttpException, forgetting @Injectable(), running a global ValidationPipe without whitelist: true, importing a module instead of exporting the provider, calling async config before ConfigModule.forRoot(), leaving real services in unit tests instead of overrideProvider(), and letting E2E tests share database state.
A separate section covers NestJS 11 changes: Node.js 20 as the floor, Express v5 with named wildcards and optional params in braces, the updated Fastify v5 adapter, and dynamic modules that produce separate instances when the same config is imported more than once. On Express v4 or Node.js below 20, some of that advice has to wait until you upgrade.
What it helps with
- split a module into controller, service and providers without tight coupling
- turn on a global
ValidationPipewithwhitelistandforbidNonWhitelisted - break a circular dependency with
forwardRef() - swap a real service for a mock via
overrideProvider()in a unit test - move routes to Express v5 named wildcards
Example prompts for the agent
- Write a
UsersModulewith a controller and service, and export the provider for other modules - Review my controller: are the pipes and exception filters wired correctly?
- Refactor this service for NestJS 11 and account for the Express v5 changes
How to install nestjs-best-practices
1Skills CLI (Vercel)
npx skills add ejirocodes/agent-skills --skill nestjs-best-practices -a claude-code2Manually: put the files in place
~/.claude/skills/nestjs-best-practices/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/nestjs-best-practices/
1Skills CLI (Vercel)
npx skills add ejirocodes/agent-skills --skill nestjs-best-practices -a codex2Manually: put the files in place
.agents/skills/nestjs-best-practices/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add ejirocodes/agent-skills --skill nestjs-best-practices -a cursor2Manually: put the files in place
.cursor/skills/nestjs-best-practices/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install ejirocodes/agent-skills nestjs-best-practices2Manually: put the files in place
.github/skills/nestjs-best-practices/SKILL.md1Skills CLI (Vercel)
npx skills add ejirocodes/agent-skills --skill nestjs-best-practices -a gemini-cli2Platform CLI
gemini skills install https://github.com/ejirocodes/agent-skills --path nestjs/skills/nestjs-best-practicesManually: put the files in place
.devin/skills/nestjs-best-practices/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add ejirocodes/agent-skills --skill nestjs-best-practices -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about nestjs-best-practices
How do I install nestjs-best-practices in Claude Code?
Run npx skills add ejirocodes/agent-skills --skill nestjs-best-practices -a claude-code. The skill lands in ~/.claude/skills/nestjs-best-practices/SKILL.md.
What does nestjs-best-practices do?
It gives the agent a NestJS 11 reference: architecture, request lifecycle, validation, authentication, databases, testing, OpenAPI and GraphQL, microservices. The agent leans on it while writing and reviewing code.
Which Node.js and Express versions does NestJS 11 need?
Node.js 20 at minimum. Under Express v5 wildcards must be named, for instance *splat, and optional params go in braces: /:file{.:ext}.
Source text
SKILL.md · MIT
---
name: nestjs-best-practices
description: "NestJS 11+ best practices for enterprise Node.js applications with TypeScript. Use when writing, reviewing, or refactoring NestJS controllers, services, modules, or APIs. Triggers on: NestJS modules, controllers, providers, dependency injection, @Injectable, @Controller, @Module, middleware, guards, interceptors, pipes, exception filters, ValidationPipe, class-validator, class-transformer, DTOs, JWT authentication, Passport strategies, @nestjs/passport, TypeORM entities, Prisma client, Drizzle ORM, repository pattern, circular dependencies, forwardRef, @nestjs/swagger, OpenAPI decorators, GraphQL resolvers, @nestjs/graphql, microservices, TCP transport, Redis transport, NATS, Kafka, NestJS 11 breaking changes, Express v5 migration, custom decorators, ConfigService, @nestjs/config, health checks, or NestJS testing patterns."
license: MIT
metadata:
author: ejirocodes
version: '1.0.0'
---
# NestJS 11 Best Practices
## Quick Reference
| Topic | When to Use | Reference |
|-------|-------------|-----------|
| **Core Architecture** | Modules, Providers, DI, forwardRef, custom decorators | [core-architecture.md](references/core-architecture.md) |
| **Request Lifecycle** | Middleware, Guards, Interceptors, Pipes, Filters | [request-lifecycle.md](references/request-lifecycle.md) |
| **Validation & Pipes** | DTOs, class-validator, ValidationPipe, transforms | [validation-pipes.md](references/validation-pipes.md) |
| **Authentication** | JWT, Passport, Guards, Local/OAuth strategies, RBAC | [authentication.md](references/authentication.md) |
| **Database** | TypeORM, Prisma, Drizzle ORM, repository patterns | [database-integration.md](references/database-integration.md) |
| **Testing** | Unit tests, E2E tests, mocking providers | [testing.md](references/testing.md) |
| **OpenAPI & GraphQL** | Swagger decorators, resolvers, subscriptions | [openapi-graphql.md](references/openapi-graphql.md) |
| **Microservices** | TCP, Redis, NATS, Kafka patterns | [microservices.md](references/microservices.md) |
## Essential Patterns
### Module with Providers
```typescript
@Module({
imports: [DatabaseModule],
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService], // Export for other modules
})
export class UsersModule {}
```
### Controller with Validation
```typescript
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
return this.usersService.findOne(id);
}
}
```
### DTO with Validation
```typescript
import { IsEmail, IsString, MinLength, IsOptional } from 'class-validator';
export class CreateUserDto {
@IsEmail()
email: string;
@IsString()
@MinLength(8)
password: string;
@IsOptional()
@IsString()
name?: string;
}
```
### Exception Filter
```typescript
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const status = exception.getStatus();
response.status(status).json({
statusCode: status,
message: exception.message,
timestamp: new Date().toISOString(),
});
}
}
```
### Guard with JWT
```typescript
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
canActivate(context: ExecutionContext) {
return super.canActivate(context);
}
}
```
## NestJS 11 Breaking Changes
- **Express v5**: Wildcards must be named (e.g., `*splat`), optional params use braces `/:file{.:ext}`
- **Node.js 20+**: Minimum required version
- **Fastify v5**: Updated adapter for Fastify users
- **Dynamic Modules**: Same module with identical config imported multiple times = separate instances
## Common Mistakes
1. **Not using `forwardRef()` for circular deps** - Causes "cannot resolve dependency" errors; wrap in `forwardRef(() => ModuleName)`
2. **Throwing plain errors instead of HttpException** - Loses status codes, breaks exception filters; use `throw new BadRequestException('message')`
3. **Missing `@Injectable()` decorator** - Provider won't be injectable; always decorate services
4. **Global ValidationPipe without `whitelist: true`** - Allows unexpected properties; set `whitelist: true, forbidNonWhitelisted: true`
5. **Importing modules instead of exporting providers** - Use `exports` array to share providers across modules
6. **Async config without `ConfigModule.forRoot()`** - ConfigService undefined; import ConfigModule in AppModule
7. **Testing without `overrideProvider()`** - Uses real services in unit tests; mock dependencies with `overrideProvider(Service).useValue(mock)`
8. **E2E tests sharing database state** - No isolation between tests; use transactions or truncate tables in beforeEach
© ejirocodes · MIT · ejirocodes/agent-skills
Similar skills
All skills for Backend and APIs →nestjs-best-practices by other authors comes first.