| name | nestjs-coding-standard |
| description | This skill should be activated when reviewing NestJS/TypeScript code or enforcing coding standards in NestJS 11.x services. It covers naming conventions, TypeScript strictness, DTO patterns, module organization, and error handling. |
| allowed-tools | Read |
| metadata | {"triggers":"NestJS coding standard, NestJS code review, NestJS best practices, TypeScript backend standard, NestJS style","related-skills":"nestjs-api, code-reviewer, security-reviewer","domain":"backend","role":"specialist","scope":"review","output-format":"report"} |
| last-reviewed | 2026-03-15 |
Iron Law: Always load the nestjs-api skill before writing NestJS code; never generate Prisma or Fastify patterns without consulting current documentation.
NestJS + TypeScript Coding Standards
Standards for readable, maintainable TypeScript code in NestJS 11.x + Fastify services.
Core Principles
- Prefer clarity over cleverness
- Immutable by default; minimize shared mutable state
- Fail fast with meaningful exceptions
- Consistent naming and module structure
Key Rules
| Rule | Standard |
|---|
| Naming | Classes: PascalCase, files: kebab-case, constants: UPPER_SNAKE_CASE |
| TypeScript Strictness | strict: true always; no any, use unknown with type guards |
| Immutability | readonly on injected dependencies; spread for updates, never mutate |
| Error Handling | Custom exceptions extend BaseException; log + rethrow, never swallow |
| DTOs | class-validator on every field; separate Create/Update/Response DTOs |
| Modules | Feature-first modules; explicit imports/exports, no implicit dependencies |
| Logging | Logger per class with structured key-value pairs; never log PII |
| Testing | AAA pattern (Arrange-Act-Assert); one assertion focus per test |
| Null Handling | Use null over undefined for explicit absence; validate with DTOs |
| Generics | Explicit return types on public methods; use type inference for locals |
| Environment | All required env vars in .env with working defaults; no ?? fallbacks in config code; .env written via Bash (hooks block Write/Edit) |
| Prisma 7.x | provider = "prisma-client" with output path; no url in schema; use prisma.config.ts; PrismaService via composition (not inheritance) with @prisma/adapter-pg |
Project Structure
src/
main.ts → app.module.ts
config/ → common/ → core/ → features/
features/<entity>/
<entity>.module.ts
<entity>.controller.ts
<entity>.service.ts
dto/
repository/
Code Examples & Detailed Patterns
For naming examples, TypeScript strictness, immutability patterns, DTO validation, module organization, error handling, service patterns, controller patterns, logging, formatting, code smells, and testing expectations, Read reference/nestjs-standards-examples.md.
Remember: Keep code intentional, typed, and observable. Optimize for maintainability over micro-optimizations unless proven necessary.
TypeScript Immutability Rules
CRITICAL — Never mutate objects or arrays directly in NestJS services/controllers.
const updatedUser = { ...user, name: 'New Name', updatedAt: new Date() }
const updatedItems = [...items, newItem]
user.name = 'New Name'
items.push(newItem)
Why: Prisma entities and DTOs passed between layers can be shared references. Mutating them corrupts upstream state silently.
No Magic Numbers
const MAX_RETRY_ATTEMPTS = 3
const DEBOUNCE_DELAY_MS = 500
const DEFAULT_PAGE_SIZE = 20
if (retryCount > 3) { }
setTimeout(fn, 500)
.limit(20)
Early Returns Over Deep Nesting
if (!user) throw new NotFoundException('User not found')
if (!user.isActive) throw new ForbiddenException('Account suspended')
return this.userRepo.findOrders(user.id)
if (user) {
if (user.isActive) {
if (order) {
if (order.isPaid) { ... }
}
}
}
Parallel Async (use Promise.all)
const [user, orders, stats] = await Promise.all([
this.userService.findById(userId),
this.orderService.findByUser(userId),
this.statsService.forUser(userId),
])
const user = await this.userService.findById(userId)
const orders = await this.orderService.findByUser(userId)
const stats = await this.statsService.forUser(userId)
Error Handling
Exception hierarchy: Use HttpException subclasses (NotFoundException, BadRequestException). Global exception filter returns RFC 9457 ProblemDetail.
Validation failures: Use class-validator decorators on DTOs. Global ValidationPipe auto-returns 422 with field-level details.