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).
From nestnpx claudepluginhub fabiensalles/claude-marketplace --plugin nestThis skill uses the workspace's default tool permissions.
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Migrates code, prompts, and API calls from Claude Sonnet 4.0/4.5 or Opus 4.1 to Opus 4.5, updating model strings on Anthropic, AWS, GCP, Azure platforms.
Generates FastAPI project templates with async routes, dependency injection, Pydantic schemas, repository patterns, middleware, and config for PostgreSQL/MongoDB backends.
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 |