# Nestjs Coding Standard

> 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.

- Skill: `kumaran-is/nestjs-coding-standard` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add kumaran-is/nestjs-coding-standard`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kumaran-is/nestjs-coding-standard/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: kumaran-is (https://skillmd.com/u/kumaran-is)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/kumaran-is/nestjs-coding-standard

---


**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.

```typescript
// ✅ ALWAYS: Spread operator for object updates
const updatedUser = { ...user, name: 'New Name', updatedAt: new Date() }
const updatedItems = [...items, newItem]

// ❌ NEVER: Direct mutation
user.name = 'New Name'    // BAD — breaks immutability, causes subtle bugs
items.push(newItem)       // BAD — mutates in place, unpredictable in reactive chains
```

**Why:** Prisma entities and DTOs passed between layers can be shared references. Mutating them corrupts upstream state silently.

### No Magic Numbers

```typescript
// ✅ GOOD: Named constants
const MAX_RETRY_ATTEMPTS = 3
const DEBOUNCE_DELAY_MS = 500
const DEFAULT_PAGE_SIZE = 20

// ❌ BAD: Magic literals
if (retryCount > 3) { }
setTimeout(fn, 500)
.limit(20)
```

### Early Returns Over Deep Nesting

```typescript
// ✅ GOOD: Guard clauses, max 2 levels nesting
if (!user) throw new NotFoundException('User not found')
if (!user.isActive) throw new ForbiddenException('Account suspended')
return this.userRepo.findOrders(user.id)

// ❌ BAD: 4+ levels of nesting
if (user) {
  if (user.isActive) {
    if (order) {
      if (order.isPaid) { ... }
    }
  }
}
```

### Parallel Async (use Promise.all)

```typescript
// ✅ GOOD: Parallel when operations are independent
const [user, orders, stats] = await Promise.all([
  this.userService.findById(userId),
  this.orderService.findByUser(userId),
  this.statsService.forUser(userId),
])

// ❌ BAD: Sequential when not needed
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.

