# How to Resolve Circular Dependencies in NestJS: Complete Guide to forwardRef()

> Resolve circular dependencies in NestJS by implementing forwardRef() to defer class resolution and complete your module graph.

- Repository: [nestjs/nest](https://github.com/nestjs/nest)
- Tags: tutorial
- Published: 2026-03-01

---

**Use NestJS's `forwardRef()` utility to wrap imports and injections on both sides of a bidirectional relationship, deferring class resolution until the dependency injection container completes the module graph.**

Circular dependency resolution in NestJS is essential when two modules or providers must reference each other directly. Without proper handling, the synchronous nature of JavaScript module evaluation causes the second import to resolve as `undefined`, triggering runtime errors. The `nestjs/nest` source code implements a lazy-evaluation strategy through **forward references** that delays instantiation until after the scanner builds the complete dependency graph.

## How Circular Dependencies Break at Runtime

When Module A imports Module B, and Module B imports Module A, the JavaScript module loader evaluates whichever file is imported first. The second file evaluates to `undefined` because its dependencies haven't finished loading yet. NestJS detects this scenario during the scanning phase and throws a `CircularDependencyException` from [`packages/core/errors/exceptions/circular-dependency.exception.ts`](https://github.com/nestjs/nest/blob/main/packages/core/errors/exceptions/circular-dependency.exception.ts), prompting developers to use `forwardRef()`:

```ts
export class CircularDependencyException extends RuntimeException {
  constructor(context?: string) {
    const ctx = context ? ` inside ${context}` : ``;
    super(
      `A circular dependency has been detected${ctx}. Please, make sure that each side of a bidirectional relationships are decorated with "forwardRef()".`,
    );
  }
}

```

## The forwardRef() Mechanism in the NestJS Core

NestJS solves circular dependency resolution through a deferred reference pattern implemented across the common utilities and core scanner.

### Creating Forward References with forwardRef()

The `forwardRef()` utility in [`packages/common/utils/forward-ref.util.ts`](https://github.com/nestjs/nest/blob/main/packages/common/utils/forward-ref.util.ts) accepts a callback that returns a class and wraps it in an object implementing the `ForwardReference` interface:

```ts
export const forwardRef = (fn: () => any): ForwardReference => ({
  forwardRef: fn,
});

```

This wrapper prevents immediate evaluation of the class constructor, allowing the module system to finish loading all files before resolving the actual dependency.

### Scanner Detection and Resolution

The module scanner in [`packages/core/scanner.ts`](https://github.com/nestjs/nest/blob/main/packages/core/scanner.ts) detects forward references using the `isForwardReference()` type guard:

```ts
private isForwardReference(module: ModuleDefinition): module is ForwardReference {
  return module && !!(module as ForwardReference).forwardRef;
}

```

When the scanner encounters a forward reference during `scanForModules`, it invokes the stored callback to retrieve the real class:

```ts
if (this.isForwardReference(moduleDefinition)) {
  moduleDefinition = (moduleDefinition as ForwardReference).forwardRef();
}

```

The scanner also handles forward references when inserting imports via `insertImport()`:

```ts
if (this.isForwardReference(related)) {
  return this.container.addImport(related.forwardRef(), token);
}

```

This lazy resolution ensures that both modules exist in the container's registry before Nest attempts to wire their dependencies.

## Implementing Circular Dependency Resolution in Practice

Apply `forwardRef()` to both sides of any bidirectional relationship—whether between modules or between individual providers.

### Resolving Module-to-Module Circular Imports

When two modules depend on each other's services, wrap the import in `forwardRef()` within each module's `@Module()` decorator. The integration tests in `integration/testing-module-override/circular-dependency/` demonstrate this pattern:

```ts
// a.module.ts
import { Module, forwardRef } from '@nestjs/common';
import { BModule } from './b.module';

@Module({
  imports: [forwardRef(() => BModule)],
  providers: [AService],
  exports: [AService],
})
export class AModule {}

```

```ts
// b.module.ts
import { Module, forwardRef } from '@nestjs/common';
import { AModule } from './a.module';

@Module({
  imports: [forwardRef(() => AModule)],
  providers: [BService],
  exports: [BService],
})
export class BModule {}

```

Both modules import each other using `forwardRef(() => OtherModule)`. The scanner executes these callbacks only after collecting all module definitions, breaking the circularity safely.

### Resolving Provider-to-Provider Circular Injection

For circular dependencies between individual providers within the same or different modules, use `@Inject()` combined with `forwardRef()` in the constructor:

```ts
// circular.service.ts
import { Injectable, forwardRef, Inject } from '@nestjs/common';
import { InputService } from './input.service';

@Injectable()
export class CircularService {
  constructor(
    @Inject(forwardRef(() => InputService))
    private readonly input: InputService,
  ) {}
}

```

```ts
// input.service.ts
import { Injectable, forwardRef, Inject } from '@nestjs/common';
import { CircularService } from './circular.service';

@Injectable()
export class InputService {
  constructor(
    @Inject(forwardRef(() => CircularService))
    private readonly circular: CircularService,
  ) {}
}

```

Each provider injects the other through `@Inject(forwardRef(() => TargetService))`. Nest resolves these callbacks after instantiating the full provider graph, located in examples such as `integration/inspector/src/circular-modules/`.

## Summary

- **Forward references defer evaluation**: The `forwardRef()` utility in [`packages/common/utils/forward-ref.util.ts`](https://github.com/nestjs/nest/blob/main/packages/common/utils/forward-ref.util.ts) wraps classes in callbacks that execute after the module graph is complete.
- **Scanner integration**: [`packages/core/scanner.ts`](https://github.com/nestjs/nest/blob/main/packages/core/scanner.ts) detects forward references via `isForwardReference()` and resolves them during module scanning and import insertion.
- **Module circularity**: Use `forwardRef(() => OtherModule)` in the `imports` array of both modules' `@Module()` decorators.
- **Provider circularity**: Use `@Inject(forwardRef(() => OtherService))` in both providers' constructors to break the instantiation deadlock.
- **Error guidance**: If you omit `forwardRef()` on either side, Nest throws a `CircularDependencyException` from [`packages/core/errors/exceptions/circular-dependency.exception.ts`](https://github.com/nestjs/nest/blob/main/packages/core/errors/exceptions/circular-dependency.exception.ts) identifying the problematic context.

## Frequently Asked Questions

### What causes circular dependency errors in NestJS?

Circular dependency errors occur when two modules or providers import each other directly without lazy resolution. JavaScript's synchronous module system evaluates the first imported file completely before the second, causing the second import to be `undefined` when the first file references it. NestJS detects this undefined resolution and throws a `CircularDependencyException` to prevent runtime injection failures.

### When should I use forwardRef() versus restructuring my code?

Use `forwardRef()` when the bidirectional relationship is architecturally necessary—such as when Module A exposes services that Module B extends, and Module B provides utilities that Module A consumes. If the circularity indicates a design flaw where both modules share too many concerns, refactor by extracting common logic into a third shared module instead of using forward references.

### Can I use forwardRef() with custom providers?

Yes. Apply `forwardRef()` within the `@Module()` providers array when using custom provider syntax such as `useFactory`, `useClass`, or `useValue`. For factory providers that depend on circular services, wrap the injected token in `forwardRef(() => CircularService)` within the factory's inject array or constructor injection parameters.

### How does NestJS detect circular dependencies at runtime?

The scanner in [`packages/core/scanner.ts`](https://github.com/nestjs/nest/blob/main/packages/core/scanner.ts) validates module references during the bootstrap phase. If a forward reference callback returns `undefined` when invoked, or if the container encounters an unresolvable token during provider instantiation, Nest throws a `CircularDependencyException`. This validates that developers have explicitly marked both sides of circular relationships with `forwardRef()`, ensuring intentional rather than accidental circular architecture.