Help us improve
Share bugs, ideas, or general feedback.
From nest
ACTIVATE when writing domain layer code in a NestJS project, defining ports/adapters, or structuring bounded contexts as NestJS modules. ACTIVATE for 'domain layer', 'DDD NestJS', 'port', 'adapter', 'bounded context', 'domain purity'. Covers: strict domain layer purity (no NestJS decorators, no ORM, no HTTP in domain), directory structure (domain/application/infrastructure), ports and adapters pattern with Symbol tokens, dependency direction rules. DO NOT use for: NestJS module/controller setup (see nest-conventions), general TypeScript DDD (see ddd-ts-fp).
npx claudepluginhub fabiensalles/claude-marketplace --plugin nestHow this skill is triggered — by the user, by Claude, or both
Slash command
/nest:nest-ddd-conventionsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> **See also**: `php-ddd-conventions` for the same principles in PHP/Symfony context.
Implements Clean Architecture, DDD, and Hexagonal Architecture patterns in NestJS/TypeScript apps for complex backend structuring, domain layers with entities/aggregates, ports/adapters, use cases, and refactoring anemic models.
Applies opinionated NestJS conventions for backends: modules, dependency injection, controllers/services, DTOs with class-validator, guards/interceptors/pipes, JWT auth, TypeORM/Prisma. Use for REST/GraphQL APIs.
Provides NestJS patterns and best practices for architecture (modular, clean, CQRS), databases (Prisma, TypeORM, repository), security (JWT, guards), validation, errors, testing, caching, and queues.
Share bugs, ideas, or general feedback.
See also:
php-ddd-conventionsfor the same principles in PHP/Symfony context.
The domain layer MUST NOT depend on infrastructure concerns.
@Injectable(), @Controller(), @Module(), @Inject()Request, Response, @Body(), @Param(), @Query()pgTable), Drizzle query builders, PrismaClientConfigService, HttpService, Logger (NestJS)string, number, Date, Record, etc.)packages/shared (Zod schemas + inferred types)as const objectssrc/
├── domain/ # PURE — no framework imports
│ ├── model/ # Entities, value objects, aggregates
│ ├── port/ # Interfaces (repository contracts)
│ ├── service/ # Domain services (pure logic)
│ └── error/ # Domain exceptions
│
├── application/ # Use cases — orchestration
│ └── use-case/ # May use @Injectable() for DI
│
└── infrastructure/ # Framework & external — implements ports
├── persistence/ # Drizzle repositories (implements port/)
├── http/ # Controllers, guards, pipes
└── config/ # NestJS module, providers
Each bounded context maps to a NestJS module:
// ✅ CORRECT - One module per bounded context
@Module({
controllers: [ReceiptController],
providers: [
GenerateReceiptUseCase,
{ provide: RECEIPT_REPOSITORY, useClass: DrizzleReceiptRepository },
],
})
export class ReceiptModule {}
Controllers → Use Cases → Domain Services → Domain Ports
↑
Infrastructure Adapters ────────────────────────┘
(implement domain ports)
Domain NEVER imports from infrastructure. Infrastructure imports from domain.
// ✅ domain/port/receipt-repository.ts — pure interface
export interface ReceiptRepository {
findByTenantId(tenantId: TenantId): Promise<Receipt[]>;
save(receipt: Receipt): Promise<void>;
}
export const RECEIPT_REPOSITORY = Symbol('ReceiptRepository');
// ✅ infrastructure/persistence/drizzle-receipt-repository.ts
import { Injectable, Inject } from '@nestjs/common';
import { ReceiptRepository } from '../../domain/port/receipt-repository';
@Injectable()
export class DrizzleReceiptRepository implements ReceiptRepository {
constructor(@Inject('DRIZZLE') private readonly db: DrizzleDatabase) {}
async findByTenantId(tenantId: TenantId): Promise<Receipt[]> {
// Drizzle query here — infrastructure concern
}
async save(receipt: Receipt): Promise<void> {
// Drizzle insert here
}
}
| Layer | Can import from | Cannot import from |
|---|---|---|
| Domain | Pure TS, shared DTOs | NestJS, Drizzle, HTTP, any framework |
| Application | Domain, NestJS DI | Infrastructure directly |
| Infrastructure | Domain, NestJS, Drizzle | — |
| Rule | Principle |
|---|---|
| Domain purity | No decorators, no ORM, no HTTP in domain |
| Ports & adapters | Interfaces in domain, implementations in infrastructure |
| Bounded context | 1 NestJS module = 1 bounded context |
| Dependency direction | Always inward: infra → application → domain |