Skip to main content

Circular dependency between modules

What a circular dependency is

A circular dependency happens when two (or more) modules or providers depend on each other, directly or through a chain.

For example:

javascript
AuthModuleUsersModuleAuthModule

or

javascript
AuthServiceUsersServiceAuthService

An example of the problem with modules

javascript
// auth.module.ts @Module({ imports: [UsersModule], // AuthModule depends on UsersModule providers: [AuthService], }) export class AuthModule {}
javascript
// users.module.ts @Module({ imports: [AuthModule], // UsersModule depends on AuthModule providers: [UsersService], }) export class UsersModule {}

On startup:

javascript
Error: Nest cannot create the module instance. A circular dependency has been detected between modules.

NestJS can't build the dependency graph, because each module is waiting for the other to be created.

Why this happens

Nest builds a Dependency Graph:

  • When AuthModule imports UsersModule, Nest first has to create UsersModule.
  • But UsersModule, in turn, imports AuthModule, and the process loops.

As a result, NestJS doesn't know where to start, and throws an error about the circular dependency.

The same problem can happen with providers

javascript
@Injectable() export class AuthService { constructor(private readonly usersService: UsersService) {} } @Injectable() export class UsersService { constructor(private readonly authService: AuthService) {} }

Here NestJS also gets "stuck" creating the instances:

  • AuthService needs UsersService,
  • but creating UsersService needs AuthService.

How to solve the problem

NestJS provides a special tool, forwardRef().

The fix for modules

Use forwardRef() when importing the dependent module:

javascript
// auth.module.ts @Module({ imports: [forwardRef(() => UsersModule)], // the key change providers: [AuthService], exports: [AuthService], }) export class AuthModule {}
javascript
// users.module.ts @Module({ imports: [forwardRef(() => AuthModule)], // the mutual dependency is now allowed providers: [UsersService], exports: [UsersService], }) export class UsersModule {}

Now Nest knows these modules reference each other "lazily", and can build the dependency graph correctly.

The fix for services

Also with forwardRef():

javascript
@Injectable() export class AuthService { constructor( @Inject(forwardRef(() => UsersService)) private readonly usersService: UsersService, ) {} } @Injectable() export class UsersService { constructor( @Inject(forwardRef(() => AuthService)) private readonly authService: AuthService, ) {} }

forwardRef() tells the DI container:

"Don't create this dependency right now, create it once it's actually needed."

How this works internally

  • With a normal dependency, Nest creates instances at initialization time.
  • With forwardRef(), it registers a lazy reference, and fills in the dependency later, once all the providers are available.

Design tips (to avoid cycles)

  1. Split responsibilities: if two modules depend on each other, the logic was probably split poorly. → Pull the shared part out into a third module (e.g. SharedModule or CoreModule).
  2. Export only what's needed. Don't export entire modules unnecessarily, just the specific services.
  3. Avoid mutual dependencies between services. Sometimes a direct reference can be replaced with events, callbacks, or repositories.

What happens if you don't use forwardRef()

NestJS:

  • won't be able to resolve the dependencies;

  • will throw:

    javascript
    Nest can't resolve dependencies of the AuthService (?). Please make sure that the argument UsersService at index [0] is available in the AuthModule context.

And the application simply won't start.

Summary

PointDescription
What it isA situation where two modules or services depend on each other
CauseNest can't determine the order to create the instances in
FixUse forwardRef(() => TargetModule) or @Inject(forwardRef(() => TargetService))
Better approachRethink the architecture and move the shared logic into a separate module
If left unfixedA startup error: "Circular dependency detected"

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.