A circular dependency exists when:
Module A → Module B → Module C → Module A
Or the simplest case:
Module A ⇄ Module B
These cycles violate the principle of unidirectional dependency flow and create tightly coupled code that's difficult to test, maintain, and refactor.
Stellarion uses graph-based cycle detection:
The analysis uses KuzuDB for efficient graph traversal, examining:
Stellarion enforces strict standards for circular dependencies:
| Count | Severity | Assessment |
|---|---|---|
| 0 | Excellent | Clean architecture |
| 1-3 | Warning | Needs attention |
| >3 | Critical | Architectural problem |
Stellarion's stance: Zero tolerance for circular dependencies in production code.
undefined for values not yet initializeduser.ts → utils.ts → user.ts
A "utils" module that imports from modules it's supposed to serve.
OrderService → PaymentService → OrderService
Services that call each other bidirectionally.
types.ts → models.ts → types.ts
Type definitions that depend on implementations.
Introduce an abstraction (interface) that both modules depend on:
// Before: A → B → A (cycle)
// After:
// A → Interface ← B (no cycle)
interface PaymentProcessor {
process(order: Order): Promise<void>;
}
Move shared code to a new module that both can import:
// Before: A ⇄ B (cycle)
// After:
// A → Common ← B (no cycle)
// common.ts contains shared types and utilities
If two modules are truly inseparable, they may belong together:
// Before: userAuth.ts ⇄ userProfile.ts
// After: user.ts (single module)
Replace direct calls with events or callbacks:
// Before: OrderService.complete() calls PaymentService.charge()
// PaymentService.refund() calls OrderService.update()
// After: Both publish/subscribe to events
eventBus.emit('order.completed', order);
eventBus.on('payment.refunded', handleRefund);
Defer dependency resolution to runtime:
// Instead of top-level import
// import { UserService } from './userService';
// Use dynamic import when needed
const { UserService } = await import('./userService');
When Stellarion detects circular dependencies:
eslint-plugin-import to detect cyclesFor the complete metrics reference, see Stellarion Quality Metrics.
Maintainability Index
The Maintainability Index (MI) is a composite metric that combines multiple code characteristics into a single score representing how maintainable your code is. Originally developed by Oman and Hagemeister in 1991, it provides a holistic view of code health on a 0-100 scale.
Unused Code Detection
Unused code—also known as dead code—refers to code that exists in your codebase but is never executed or referenced. This includes unreachable functions, unused variables, obsolete imports, and orphaned exports. While harmless at runtime, unused code degrades maintainability, increases bundle sizes, and creates confusion for developers.