| name | NestJS Architecture |
|---|---|
| description | Module organization, Dependency Injection patterns, and Project Structure. |
| metadata | {"labels": ["nestjs", "architecture", "modularity"], "triggers": {"files": ["**/*.module.ts", "main.ts"], "keywords": ["Module", "forRoot", "forFeature", "Dependency Injection"]}} |
NestJS Architecture Standards
Priority: P0 (FOUNDATIONAL)
Core architectural patterns and dependency injection standards for scalable NestJS applications.
Core Principles
- Modularity: Every feature must be encapsulated in its own
@Module. - Do:users.module.ts,auth.module.ts. - Don't: Everything inapp.module.ts. - Dependency Injection (DI): Invert control. Never manually instantiate classes (e.g.,
new Service()). - Use: Constructor injectionconstructor(private readonly service: Service). - Scalability: Use Feature Modules for domain logic and Core/Shared Modules for reusable utilities.
Module Configuration
Dynamic Modules
- Modern Pattern: Use
ConfigurableModuleBuilderclass to auto-generateforRoot/registermethods properly. - Reference: See Dynamic Module Builder Implementation for the boilerplate code.
- Conventions:
forRoot: Global configurations (Db, Config).register: Per-instance configurations.forFeature: Extending a module with specific providers/entities.
Circular Dependencies
- Avoid: Re-architect to move shared logic to a common module.
- Constraint: If unavoidable, use
forwardRef(() => ModuleName)on both sides of the import.
Advanced Providers
- Factory Providers: Use
useFactoryheavily for providers dependent on configuration or async operations. - Aliasing: Use
useExistingto provide backward compatibility or abstract different implementations.
Scopes & Lifecycle
- Default: Singleton. Best performance.
- Request Scope: Use
Scope.REQUESTsparingly. - Performance Warning: Request scope bubbles up. If a Service is request-scoped, every controller injecting it becomes request-scoped, triggering re-instantiation per request (~5-10% latency overhead).
- Multi-tenancy: If request-scope is needed (e.g. Tenant ID header), use Durable Providers (
durable: true) withContextIdFactoryto reuse DI sub-trees. - Shutdown:
SIGTERMdoesn't trigger cleanup by default. - Mandatory: Call
app.enableShutdownHooks()inmain.ts.
Structure & Organization
- Feature Modules: Domain logic (
ShopModule,AuthModule). Encapsulated. - Shared Module: Reusable providers (
DateService,MathService) exported to other modules. Stateless. - Core Module:
- Role: Global infrastructure setup ONE TIME (Interceptors, Filters, Loggers).
- Rule: Import
CoreModuleonly inAppModule. - Contents:
APP_INTERCEPTOR,APP_FILTER,APP_GUARDproviders.
Reliability & Observability
- Health Checks: Mandatory for K8s/Docker.
- Tool: Use
@nestjs/terminus. Expose/healthendpoint checking DB, Cache (Redis), and Memory. - Structured Logging:
- Warning: Default NestJS logger is unstructured text.
- Standard: Use
nestjs-pinofor JSON-formatted logs with automaticreq-idcorrelation and request duration tracking. - Context: Inject
Loggerinto services to keep traces connected.