2.0 KiB
2.0 KiB
title, impact, impactDescription, tags
| title | impact | impactDescription | tags |
|---|---|---|---|
| Avoid Circular Dependencies | CRITICAL | #1 cause of runtime crashes | architecture, modules, dependencies |
Avoid Circular Dependencies
Circular dependencies occur when Module A imports Module B, and Module B imports Module A (directly or transitively). NestJS can sometimes resolve these through forward references, but they indicate architectural problems and should be avoided. This is the #1 cause of runtime crashes in NestJS applications.
Incorrect (circular module imports):
// users.module.ts
@Module({
imports: [OrdersModule], // Orders needs Users, Users needs Orders = circular
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
// orders.module.ts
@Module({
imports: [UsersModule], // Circular dependency!
providers: [OrdersService],
exports: [OrdersService],
})
export class OrdersModule {}
Correct (extract shared logic or use events):
// Option 1: Extract shared logic to a third module
// shared.module.ts
@Module({
providers: [SharedService],
exports: [SharedService],
})
export class SharedModule {}
// users.module.ts
@Module({
imports: [SharedModule],
providers: [UsersService],
})
export class UsersModule {}
// orders.module.ts
@Module({
imports: [SharedModule],
providers: [OrdersService],
})
export class OrdersModule {}
// Option 2: Use events for decoupled communication
// users.service.ts
@Injectable()
export class UsersService {
constructor(private eventEmitter: EventEmitter2) {}
async createUser(data: CreateUserDto) {
const user = await this.userRepo.save(data);
this.eventEmitter.emit('user.created', user);
return user;
}
}
// orders.service.ts
@Injectable()
export class OrdersService {
@OnEvent('user.created')
handleUserCreated(user: User) {
// React to user creation without direct dependency
}
}
Reference: NestJS Circular Dependency