Nestjs
Skill nimadorostkar/Claude-Skills-collection/skills/backend/nestjs
Use when building NestJS services. Covers module structure, providers and scopes, validation pipes, guards and interceptors, TypeORM/Prisma integration, and testing.From its SKILL.md
npx -y skills add nimadorostkar/Claude-Skills-collection --skill nestjsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
SKILL.md
4.8 KB, 994 tokens by cl100k_base, as published. Nobody here has run it
NestJS
Purpose
Build NestJS applications where the module graph reflects the domain, validation happens at the edge, and cross-cutting concerns live in guards and interceptors rather than being copied into every controller.
When to Use
- Building or reviewing a NestJS service.
- Structuring modules, providers, and their scopes.
- Implementing authentication, authorization, and request validation.
- Writing unit and end-to-end tests for a Nest application.
Capabilities
- Module and provider design, including dynamic modules.
- Validation with
class-validatorand the globalValidationPipe. - Guards (authorization), interceptors (cross-cutting), filters (error mapping).
- Data access with Prisma or TypeORM, correctly scoped.
- Testing with the Nest testing module and Supertest.
Inputs
- The domain boundaries the modules should follow.
- The authentication scheme and the authorization model.
- The persistence layer.
Outputs
- Modules that encapsulate a domain and export only their public services.
- A global validation pipe with whitelisting enabled.
- Controllers that are thin, and services that contain the logic.
Workflow
- Model the modules on the domain — One module per bounded capability, exporting the services other modules may use. A module that exports everything is not a boundary.
- Enable strict validation globally —
whitelist: trueandforbidNonWhitelisted: true. Without these, a client can send extra fields and your DTO will happily carry them into the service. - Push cross-cutting concerns out of controllers — Auth in a guard, logging and timing in an interceptor, error mapping in an exception filter.
- Keep providers stateless and singleton — Request-scoped providers cascade: anything that injects one becomes request-scoped too, and performance degrades quietly.
- Test at two levels — Unit tests for services with mocked dependencies, and end-to-end tests through the real HTTP stack with a real (containerized) database.
Best Practices
ValidationPipewithoutwhitelist: trueis decoration, not validation. Extra properties pass straight through.transform: trueon the pipe converts payloads into DTO class instances — otherwise your@Typedecorators and defaults do nothing.- Circular module dependencies are a design smell.
forwardRefis an escape hatch that hides a boundary you drew wrong. - Do not inject the repository into the controller. The controller's job is HTTP; the service's job is the domain.
- Global exception filters map domain errors to HTTP status codes in one place. Throwing
HttpExceptionfrom a service couples the domain to the transport. - Use
ConfigModulewith a validation schema so a missing environment variable fails at boot.
Examples
Validation, guard, and thin controller:
// main.ts
app.useGlobalPipes(
new ValidationPipe({
whitelist: true, // strip unknown properties
forbidNonWhitelisted: true, // and reject the request if any are present
transform: true, // instantiate the DTO class
}),
);
export class CreateOrderDto {
@IsUUID() customerId!: string;
@IsArray()
@ArrayMinSize(1)
@ValidateNested({ each: true })
@Type(() => OrderLineDto)
lines!: OrderLineDto[];
}
@Controller("orders")
@UseGuards(JwtAuthGuard, TenantGuard)
export class OrdersController {
constructor(private readonly orders: OrdersService) {}
@Post()
@HttpCode(HttpStatus.CREATED)
create(@Body() dto: CreateOrderDto, @CurrentUser() user: User): Promise<OrderView> {
return this.orders.place(user.tenantId, dto);
}
}
Domain errors mapped centrally:
@Catch(DomainError)
export class DomainExceptionFilter implements ExceptionFilter {
catch(error: DomainError, host: ArgumentsHost) {
const status = {
NOT_FOUND: 404,
CONFLICT: 409,
INVALID: 422,
}[error.kind] ?? 400;
host.switchToHttp().getResponse().status(status).json({
type: `https://api.example.com/errors/${error.kind.toLowerCase()}`,
title: error.message,
status,
});
}
}
Notes
- Request-scoped providers instantiate a new instance per request and force the entire injection chain above them to do the same. Measure before using one.
- Nest's
TestingModulelets you override any provider, which is almost always preferable to mocking a module's internals. - Interceptors run around the handler and can transform the response. That makes them the right place for a response envelope — and the wrong place for business logic.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.