NestJS Module Standards
Modules organize related components together. Each module groups its controllers, services, and other providers into a cohesive unit.
File Structure
Each module follows this structure:
module-name/
├── commands/ (optional - CLI commands)
│ ├── module-action.ts
│ └── module-action-detail.ts
├── dto/
│ ├── request.dto.ts
│ └── response.dto.ts
├── entities/ (if using database)
│ └── module-name.entity.ts
├── module-name.controller.ts
├── module-name.service.ts
├── module-name.error.ts
├── module-name.log.ts
└── module-name.module.ts
Basic Module
Modules import dependencies, declare controllers, and provide services.
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
// Import other modules
import { DependencyModule } from '../dependency/dependency.module';
// Import local files
import { UserController } from './user.controller';
import { UserService } from './user.service';
import { UserEntity } from './entities/user.entity';
@Module({
imports: [
TypeOrmModule.forFeature([UserEntity]),
DependencyModule,
],
controllers: [UserController],
providers: [UserService],
exports: [UserService], // Export if other modules need it
})
export class UserModule {}
Naming Conventions
Files: kebab-case (lowercase with hyphens)
user.module.tsuser.controller.tsuser.service.ts
Classes: PascalCase with suffix
UserModuleUserControllerUserService
Operations: dot notation
user.readManyuser.readOne
Common Patterns
Circular dependencies: Use forwardRef() when two modules depend on each other.
import { Module, forwardRef } from '@nestjs/common';
@Module({
imports: [
forwardRef(() => OtherModule),
],
})
export class UserModule {}
Global modules: Mark modules as global to make their exports available everywhere.
import { Module, Global } from '@nestjs/common';
@Global()
@Module({
providers: [ConfigService],
exports: [ConfigService],
})
export class ConfigModule {}
Database entities: Register entities with TypeORM using forFeature().
@Module({
imports: [
TypeOrmModule.forFeature([UserEntity, ProfileEntity]),
],
})
export class UserModule {}
RabbitMQ handlers: Register both controllers and handlers in the controllers array.
@Module({
controllers: [UserController, UserHandler], // Both go here
providers: [UserService],
})
export class UserModule {}
Anti-Patterns
❌ Don't forget to export services
If other modules need your service, add it to exports.
// Bad - other modules can't use UserService
@Module({
providers: [UserService],
})
// Good - UserService available to other modules
@Module({
providers: [UserService],
exports: [UserService],
})
❌ Don't put handlers in providers
RabbitMQ event handlers go in controllers, not providers.
// Bad
@Module({
controllers: [UserController],
providers: [UserService, UserHandler], // WRONG!
})
// Good
@Module({
controllers: [UserController, UserHandler], // Both here
providers: [UserService],
})
❌ Don't create circular dependencies without forwardRef
Use forwardRef() for circular imports.
// Bad - circular dependency
@Module({
imports: [OtherModule], // OtherModule also imports UserModule
})
// Good - use forwardRef
@Module({
imports: [forwardRef(() => OtherModule)],
})
Other common mistakes:
- ❌ Not importing TypeOrmModule.forFeature() for entities
- ❌ Forgetting to register controllers in the module
- ❌ Not using @Global() for shared utilities (logger, config, etc.)