plugins/backend/skills/nestjs/SKILL.md
Expert skill for NestJS framework development. Covers modules, providers/DI, controllers, guards, interceptors, pipes, exception filters, request lifecycle, GraphQL integration, WebSockets, microservices, CQRS, scheduling, queues, caching, health checks, testing, and platform abstraction (Express/Fastify). WHEN: "NestJS", "nest.js", "@nestjs", "NestModule", "@Module", "@Injectable", "@Controller", "@Guard", "@UseGuards", "@UseInterceptors", "@UsePipes", "@Catch", "ExceptionFilter", "ValidationPipe", "class-validator", "NestJS testing", "TestingModule", "NestJS microservice", "NestJS GraphQL", "NestJS WebSocket", "NestJS CQRS", "NestJS guards", "NestJS interceptors", "NestJS pipes", "NestJS Swagger", "@nestjs/config", "@nestjs/typeorm", "@nestjs/mongoose", "NestJS Prisma", "NestJS BullMQ". Do NOT use for general Node.js scripting, automation, or CLI-tool questions unrelated to the NestJS framework — that's the `cli-scripting` plugin's `nodejs` skill.
npx skillsauth add chrishuffman5/domain-expert nestjsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill covers NestJS framework development (v10.x+). NestJS is a progressive, TypeScript-first Node.js framework built on Angular-inspired module architecture with a powerful dependency injection system. It provides an opinionated structure for building scalable server-side applications while supporting Express or Fastify as the underlying HTTP platform.
Classify the request:
references/architecture.md for module system, DI container, request lifecycle, decorator system, platform abstraction (Express/Fastify), guards vs middleware, interceptors vs pipesreferences/best-practices.md for testing patterns (TestingModule, mock providers), authentication (Passport+JWT), authorization (guards+CASL), database (TypeORM/Prisma), microservices, deployment, common anti-patternsoverview skill for cross-framework API design, REST principles, framework comparisonIdentify context -- Determine the specific NestJS subsystem: HTTP controllers, GraphQL resolvers, WebSocket gateways, microservice transports, or CQRS. Each has different decorators and lifecycle behavior.
Load context -- Read the relevant reference file before answering.
Analyze -- Apply NestJS-specific reasoning. Consider the request lifecycle order, DI scope propagation, module encapsulation boundaries, and the decorator metadata system.
Recommend -- Provide concrete TypeScript code examples. Always qualify trade-offs between simplicity and architecture.
Verify -- Suggest validation steps: unit tests with TestingModule, e2e tests with supertest, checking DI resolution, verifying guard/interceptor order.
NestJS organizes code into modules. Each module encapsulates a feature domain with its own controllers, providers, and imports.
@Module({
imports: [TypeOrmModule.forFeature([User]), ConfigModule],
controllers: [UsersController],
providers: [UsersService, UsersRepository],
exports: [UsersService], // only export what other modules need
})
export class UsersModule {}
imports -- other modules whose exports this module needsproviders -- DI-registered services, guards, interceptors, etc.controllers -- route handlers scoped to this moduleexports -- subset of providers re-exported for consumersKey rule: Export only what other modules actually import. Over-exporting creates hidden coupling.
NestJS DI is constructor-based by default. Providers are singleton-scoped unless overridden.
@Injectable()
export class OrdersService {
constructor(
private readonly usersService: UsersService,
@Inject('CONFIG') private readonly config: AppConfig,
) {}
}
Three scopes:
DEFAULT (singleton) -- shared across the entire app. Use for stateless services.REQUEST -- new instance per HTTP request. Use for tenant-aware or audit services. Warning: propagates upward through the injection chain.TRANSIENT -- new instance per injection point. Rare.Understanding the fixed execution order is essential for placing logic correctly:
Incoming Request
-> Middleware (Express-style, runs before routing)
-> Guards (authentication/authorization, return boolean)
-> Interceptors (before handler: transform request, start timers)
-> Pipes (validation and transformation of params/body)
-> Route Handler (your controller method)
-> Interceptors (after handler: transform response, log duration)
-> Exception Filters (catch errors thrown anywhere above)
-> Response
Scope ordering within each stage: Global -> Controller -> Route
Exception filters run in reverse scope order on error: Route -> Controller -> Global.
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll(@Query('page') page = 1, @Query('limit') limit = 20) {
return this.usersService.findAll({ page, limit });
}
@Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string) {
return this.usersService.findOne(id);
}
@Post()
@HttpCode(201)
create(@Body() dto: CreateUserDto) {
return this.usersService.create(dto);
}
@Delete(':id')
@HttpCode(204)
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
remove(@Param('id', ParseUUIDPipe) id: string) {
return this.usersService.remove(id);
}
}
Guards determine whether a request proceeds. They implement CanActivate and have access to ExecutionContext (including metadata).
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const roles = this.reflector.getAllAndOverride<string[]>('roles', [
context.getHandler(), context.getClass(),
]);
if (!roles?.length) return true;
const { user } = context.switchToHttp().getRequest();
return roles.some(role => user?.roles?.includes(role));
}
}
Guard vs Middleware: Guards have ExecutionContext and work across HTTP/WS/microservices. Middleware is HTTP-only, runs earlier. Use guards for auth; use middleware for request mutation.
Interceptors wrap the entire handler call using RxJS. They can transform both request and response.
@Injectable()
export class TransformInterceptor<T> implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
map(data => ({ data, timestamp: new Date().toISOString() })),
);
}
}
Pipes validate and transform input parameters before the handler runs.
// Global ValidationPipe -- validates all DTOs via class-validator
app.useGlobalPipes(new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
transformOptions: { enableImplicitConversion: true },
}));
Exception filters catch errors and convert them to HTTP responses.
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const status = exception instanceof HttpException
? exception.getStatus() : 500;
response.status(status).json({
success: false,
error: { code: 'ERROR', message: 'Something went wrong' },
timestamp: new Date().toISOString(),
});
}
}
Code-first approach with @nestjs/graphql and Apollo:
@Resolver(() => User)
export class UsersResolver {
constructor(private readonly usersService: UsersService) {}
@Query(() => [User])
users() { return this.usersService.findAll(); }
@Mutation(() => User)
createUser(@Args('input') input: CreateUserInput) {
return this.usersService.create(input);
}
@Subscription(() => User)
userCreated() { return pubSub.asyncIterableIterator('userCreated'); }
}
@WebSocketGateway({ namespace: '/chat', cors: { origin: '*' } })
export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {
@WebSocketServer() server: Server;
@SubscribeMessage('sendMessage')
handleMessage(@MessageBody() payload: { room: string; message: string }) {
this.server.to(payload.room).emit('message', payload);
}
}
NestJS supports multiple transport layers: TCP, Redis, NATS, Kafka, RabbitMQ, gRPC.
// Hybrid app -- HTTP + microservice
const app = await NestFactory.create(AppModule);
app.connectMicroservice<MicroserviceOptions>({
transport: Transport.RMQ,
options: { urls: [process.env.RABBITMQ_URL], queue: 'main' },
});
await app.startAllMicroservices();
await app.listen(3000);
// Message pattern (request/response)
@MessagePattern({ cmd: 'get_order' })
getOrder(@Payload() data: { id: string }) { ... }
// Event pattern (fire and forget)
@EventPattern('user_registered')
handleUserRegistered(@Payload() data: UserRegisteredEvent) { ... }
Separate read and write concerns with @nestjs/cqrs:
// Commands (writes)
const order = await this.commandBus.execute(new CreateOrderCommand(userId, items));
// Queries (reads)
const found = await this.queryBus.execute(new GetOrderQuery(orderId));
Use CQRS only when the domain has genuinely asymmetric read/write complexity or requires event sourcing. For CRUD-heavy services, it adds ceremony without benefit.
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
load: [appConfig, databaseConfig],
validationSchema: Joi.object({
PORT: Joi.number().default(3000),
JWT_SECRET: Joi.string().required(),
DATABASE_URL: Joi.string().required(),
}),
}),
],
})
export class AppModule {}
// URI versioning: /v1/users, /v2/users
app.enableVersioning({ type: VersioningType.URI });
@Controller({ path: 'users', version: '1' })
export class UsersControllerV1 {}
@Controller({ path: 'users', version: '2' })
export class UsersControllerV2 {}
NestJS supports Express (default) and Fastify as HTTP adapters:
// Fastify adapter -- ~20-30% throughput improvement
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
const app = await NestFactory.create<NestFastifyApplication>(AppModule, new FastifyAdapter());
await app.listen(3000, '0.0.0.0');
Caveat: Express-only middleware (e.g., passport with sessions) may need shims on Fastify.
const config = new DocumentBuilder()
.setTitle('My API')
.setVersion('1.0')
.addBearerAuth()
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
Use @nestjs/swagger CLI plugin to auto-generate @ApiProperty decorators from class-validator, reducing boilerplate.
| Decision | Guidance |
|---|---|
| Guard vs Middleware | Guards for auth (have ExecutionContext); middleware for request mutation (HTTP-only) |
| Interceptor vs Pipe | Pipes validate/transform input; interceptors wrap entire handler (modify response shape) |
| Scope selection | Default to singleton. REQUEST scope only for per-request state (tenant, audit) |
| Dynamic modules | Expose register (sync) and registerAsync (factory with DI) |
| CQRS adoption | Only for asymmetric read/write complexity or event sourcing |
| forwardRef | Last resort for circular deps -- prefer extracting shared services |
| Entity exposure | Never return ORM entities directly -- map to response DTOs |
| synchronize: true | Development only -- use migrations in production |
Load these for deep knowledge on specific topics:
references/architecture.md -- Module system, DI container, request lifecycle detail, decorator system, platform abstraction, dynamic modules, guards/interceptors/pipes/filters internals, GraphQL, WebSockets, microservices, CQRS, scheduling, queues, caching, health checks. Load when: architecture questions, lifecycle ordering, DI issues, integration setup.references/best-practices.md -- Testing patterns (TestingModule, mock providers, e2e), authentication (Passport+JWT, refresh tokens, OAuth2, API keys), authorization (RBAC guards, CASL policies), database patterns (TypeORM repository, Prisma service, Mongoose, transactions, migrations), microservices, deployment (Docker, PM2, graceful shutdown), performance (Fastify, caching, lazy modules), observability (Pino, OpenTelemetry, health checks), common anti-patterns. Load when: "how should I test", auth setup, database patterns, deployment, performance tuning.tools
kubectl command-line usage and scripting: kubeconfig and context management, output formats (jsonpath, custom-columns, go-template), all major verbs (get, describe, apply, delete, exec, logs, port-forward, rollout, scale, drain), workload resources, config/storage, networking, RBAC, node management, debugging (CrashLoopBackOff, ImagePullBackOff, OOMKilled), and scripting patterns (dry-run, diff, wait, jq, kustomize). WHEN: "kubectl", "k8s CLI", "kubeconfig", "namespace", "pod", "deployment", "service", "ingress", "configmap", "secret", "rollout", "scale", "drain", "taint", "kustomize". Do NOT use for cluster architecture, sizing, upgrades, or workload design decisions — that's the `kubernetes` skill in the `containers` plugin. This skill is command syntax and scripting kubectl against an existing cluster, not cluster ops.
tools
Bash 5.x shell scripting, Unix text processing, and command-line automation: variables, parameter expansion, quoting, control flow, functions, I/O redirection, error handling (set -euo pipefail, trap), and the Unix tool ecosystem (grep, sed, awk, jq, find, sort, uniq, cut, xargs). Covers process management, networking (curl, ssh, rsync, nc), file locking (flock), parallel execution, and production script patterns. WHEN: "Bash", "bash", "shell", "sh", ".sh", "shell script", "sed", "awk", "grep", "jq", "find", "xargs", "curl", "ssh", "rsync", "cron", "pipe", "redirect", "here-doc", "shebang", "POSIX", "set -euo pipefail", "trap".
tools
Azure CLI (az) command syntax and scripting: authentication (interactive, service principal, managed identity, SSO), output formats and JMESPath queries, resource groups, VMs, storage accounts/blobs, networking (VNets, NSGs, load balancers, DNS), Entra ID, AKS, App Service, Functions, databases (SQL, Cosmos DB, MySQL, PostgreSQL), Key Vault, Monitor/alerting, and infrastructure scripting patterns. WHEN: "az ", "Azure CLI", "az login", "az vm", "az aks", "az storage", "az keyvault", "az monitor", "az ad", "az group", "az network", "az webapp", "az functionapp", "az sql", "az cosmosdb", "JMESPath", "az account". Do NOT use for Azure architecture, landing zones, or multi-subscription strategy — that's the `cloud-platforms` plugin. This skill is about command syntax and scripting the CLI, not deciding what to provision.
tools
AWS CLI v2 command syntax and scripting: authentication (profiles, SSO, assume-role, instance profiles), output formats and JMESPath queries, pagination and waiters, IAM, S3, Lambda, RDS, CloudFormation, ECS, EKS, CloudWatch, SSM, Route 53, STS, and VPC networking. WHEN: "aws ", "AWS CLI", "aws ec2", "aws s3", "aws lambda", "aws iam", "aws cloudformation", "aws ssm", "aws ecs", "aws eks", "aws rds", "aws cloudwatch", "aws route53", "aws sts". Do NOT use for AWS architecture, service selection, multi-account strategy, or FinOps — that's the `cloud-platforms` plugin. This skill is about command syntax and scripting the CLI, not deciding what to provision.