New skills (14): - nestjs-best-practices: 40 priority-ranked rules (kadajett) - fastapi: Pydantic v2, async SQLAlchemy, JWT auth (jezweb) - architecture-patterns: Clean Architecture, Hexagonal, DDD (wshobson) - python-performance-optimization: Profiling and optimization (wshobson) - ai-sdk: Vercel AI SDK streaming and agent patterns (vercel) - create-agent: Modular agent architecture with OpenRouter (openrouterteam) - proactive-agent: WAL Protocol, compaction recovery, self-improvement (halthelobster) - brand-guidelines: Brand identity enforcement (anthropics) - ui-animation: Motion design with accessibility (mblode) - marketing-ideas: 139 ideas across 14 categories (coreyhaines31) - pricing-strategy: SaaS pricing and tier design (coreyhaines31) - programmatic-seo: SEO at scale with playbooks (coreyhaines31) - competitor-alternatives: Comparison page architecture (coreyhaines31) - referral-program: Referral and affiliate programs (coreyhaines31) README reorganized by domain: Code Quality, Frontend, Backend, Auth, AI/Agent Building, Marketing, Design, Meta. Mosaic Stack is not limited to coding — the Orchestrator serves coding, business, design, marketing, writing, logistics, and analysis. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
81 lines
2.0 KiB
Markdown
81 lines
2.0 KiB
Markdown
---
|
|
title: Avoid Circular Dependencies
|
|
impact: CRITICAL
|
|
impactDescription: "#1 cause of runtime crashes"
|
|
tags: 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):**
|
|
|
|
```typescript
|
|
// 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):**
|
|
|
|
```typescript
|
|
// 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](https://docs.nestjs.com/fundamentals/circular-dependency)
|