nestjs-patterns
Helps your agent build robust TypeScript backends using NestJS. It understands module, controller, and provider patterns for efficient applications.
What it does
This guide teaches how to organize and build web applications using NestJS technology. It shows how to divide code into parts (modules, controllers, services) and how to ensure received data is correct and secure.
When to use it
- ✓When starting a new web project with NestJS.
- ✓When organizing the code of an existing NestJS project.
- ✓When adding data validation or security rules to an API.
Example of what to ask your AI
“How can I organize my NestJS code to make it easy to maintain?”
Want more? Open the sections below.
How to use
The easiest way: copy the message below and paste it into Claude, ChatGPT, Cursor or any AI. It reads the skill and follows the instructions.
Skill link
Ready-to-paste message
How it works
It suggests a folder structure and code examples to separate responsibilities. It shows how to validate incoming data and how to handle errors consistently.
Installation
Easiest way: copy the skill link and paste it into Claude, ChatGPT or Cursor asking it to follow the instructions.
In the terminal (Claude Code, Codex, Cursor), in your project folder:
npx skills add affaan-m/ECC --skill nestjs-patternsOr download just the file:
curl -L https://raw.githubusercontent.com/affaan-m/ECC/main/pi/core/skills/nestjs-patterns/SKILL.md -o SKILL.mdTechnical content (original SKILL.md)
Original text by the author, straight from GitHub.
NestJS Development Patterns
Production-grade NestJS patterns for modular TypeScript backends.
When to Activate
- Building NestJS APIs or services
- Structuring modules, controllers, and providers
- Adding DTO validation, guards, interceptors, or exception filters
- Configuring environment-aware settings and database integrations
- Testing NestJS units or HTTP endpoints
Project Structure
src/
├── app.module.ts
├── main.ts
├── common/
│ ├── filters/
│ ├── guards/
│ ├── interceptors/
│ └── pipes/
├── config/
│ ├── configuration.ts
│ └── validation.ts
├── modules/
│ ├── auth/
│ │ ├── auth.controller.ts
│ │ ├── auth.module.ts
│ │ ├── auth.service.ts
│ │ ├── dto/
│ │ ├── guards/
│ │ └── strategies/
│ └── users/
│ ├── dto/
│ ├── entities/
│ ├── users.controller.ts
│ ├── users.module.ts
│ └── users.service.ts
└── prisma/ or database/
- Keep domain code inside feature modules.
- Put cross-cutting filters, decorators, guards, and interceptors in
common/. - Keep DTOs close to the module that owns them.
Bootstrap and Global Validation
async function bootstrap() {
const app = await NestFactory.create(AppModule, { bufferLogs: true });
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
transformOptions: { enableImplicitConversion: true },
}),
);
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)));
app.useGlobalFilters(new HttpExceptionFilter());
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();
- Always enable
whitelistandforbidNonWhitelistedon public APIs. - Prefer one global validation pipe instead of repeating validation config per route.
Modules, Controllers, and Providers
@Module({
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get(':id')
getById(@Param('id', ParseUUIDPipe) id: string) {
return this.usersService.getById(id);
}
@Post()
create(@Body() dto: CreateUserDto) {
return this.usersService.create(dto);
}
}
@Injectable()
export class UsersService {
constructor(private readonly usersRepo: UsersRepository) {}
async create(dto: CreateUserDto) {
return this.usersRepo.create(dto);
}
}
- Controllers should stay thin: parse HTTP input, call a provider, return response DTOs.
- Put business logic in injectable services, not controllers.
- Export only the providers other modules genuinely need.
DTOs and Validation
export class CreateUserDto {
@IsEmail()
email!: string;
@IsString()
@Length(2, 80)
name!: string;
@IsOptional()
@IsEnum(UserRole)
role?: UserRole;
}
- Validate every request DTO with
class-validator. - Use dedicated response DTOs or serializers instead of returning ORM entities directly.
- Avoid leaking internal fields such as password hashes, tokens, or audit columns.
Auth, Guards, and Request Context
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@Get('admin/report')
getAdminReport(@Req() req: AuthenticatedRequest) {
return this.reportService.getForUser(req.user.id);
}
- Keep auth strategies and guards module-local unless they are truly shared.
- Encode coarse access rules in guards, then do resource-specific authorization in services.
- Prefer explicit request types for authenticated request objects.
Exception Filters and Error Shape
@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const response = host.switchToHttp().getResponse<Response>();
const request = host.switchToHttp().getRequest<Request>();
if (exception instanceof HttpException) {
return response.status(exception.getStatus()).json({
path: request.url,
error: exception.getResponse(),
});
}
return response.status(500).json({
path: request.url,
error: 'Internal server error',
});
}
}
- Keep one consistent error envelope across the API.
- Throw framework exceptions for expected client errors; log and wrap unexpected failures centrally.
Config and Environment Validation
ConfigModule.forRoot({
isGlobal: true,
load: [configuration],
…
FAQ
What are modules, controllers, and providers?
Modules organize code, controllers handle requests, and providers (services) contain business logic.
Why is it important to validate incoming data?
To ensure the application receives only expected and secure information, preventing errors and security breaches.
How to handle errors in the application?
The guide suggests using exception filters to standardize how errors are reported, both to the user and the developer.
Details
Original description by the author
NestJS architecture patterns for modules, controllers, providers, DTO validation, guards, interceptors, config, and production-grade TypeScript backends. Use when building or reviewing a NestJS backend — modules, providers, DTO validation, guards, or interceptors.
repo: affaan-m/ECC
Popularity
- GitHub stars
- 280k
- Ranking position
- #91
- License
- MIT
- Updated
- 10/15/2026
Comments
- …
More skills from this repository
accessibility
Helps your agent create interfaces that everyone can use. Ensures websites and apps work well for people with disabilities, like those who are blind or have reduced mobility.
affaan-m/ECC
agent-architecture-audit
Makes your agent check if everything is working correctly. It finds and fixes problems in AI systems, ensuring they perform as expected.
affaan-m/ECC
agent-eval
Helps your agent compare different AI coding tools. It measures which one is faster, cheaper, and more reliable for specific tasks.
affaan-m/ECC
agent-harness-construction
Makes your agent better understand how to perform tasks. It optimizes the tools and instructions the agent uses to increase its chances of success.
affaan-m/ECC
Similar skills
api-and-interface-design
Helps create well-defined APIs and interfaces. It's useful when designing how different parts of software will communicate.
addyosmani/agent-skills
mason
Helps your agent write clean and functional code. It follows defined rules to ensure everything works as expected.
sickn33/agentic-awesome-skills
max
Lets your agent improve existing code without changing what it does. It makes the code easier to read and maintain.
sickn33/agentic-awesome-skills