intermediate
NestJS modules
Organize features with modules, imports, exports, dynamic modules, shared providers, and explicit application boundaries.
Modules are NestJS composition units decorated with `@Module()`. They declare `controllers`, `providers`, `imports` (other modules), and `exports` (providers visible to importers). The root `AppModule` wires the application graph.
@Module({
imports: [DatabaseModule, UsersModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Feature modules encapsulate a bounded context. Shared modules export cross-cutting providers (config, logging). Dynamic modules (`forRoot`, `forRootAsync`) accept configuration at bootstrap — common for database and auth setup.
On interviews: explain module boundaries versus folder structure, what `exports` controls in the DI graph, and when to use global modules (`@Global()`) sparingly.
Common pitfalls: circular imports between modules, exporting everything globally, and god modules that own unrelated features.
The trade-off is balancing simplicity, performance, safety, and operability — name which axis you optimized and what cost you accepted.
Checklist:
- One feature module per bounded context.
- Export only providers other modules need.
- Use dynamic modules for configurable infrastructure.
- Resolve circular deps with `forwardRef` only when necessary.