Circular dependency

A circular dependency occurs when two classes depend on each other. For example, class A needs class B, and class B also needs class A. Circular dependencies can arise in Nest between modules and between providers.

While circular dependencies should be avoided where possible, you can’t always do so. In such cases, Nest enables resolving circular dependencies between providers in two ways. In this chapter, we describe using forward referencing as one technique, and using the ModuleRef class to retrieve a provider instance from the DI container as another.

We also describe resolving circular dependencies between modules.

Forward reference

A forward reference allows Nest to reference classes which aren’t yet defined using the forwardRef() utility function. For example, if CatsService and CommonService depend on each other, both sides of the relationship can use @Inject() and the forwardRef() utility to resolve the circular dependency. Otherwise Nest won’t instantiate them because all of the essential metadata won’t be available. Here’s an example:

cats.service.ts

  1. @Injectable()
  2. export class CatsService {
  3. constructor(
  4. @Inject(forwardRef(() => CommonService))
  5. private commonService: CommonService,
  6. ) {}
  7. }
  1. @Injectable()
  2. @Dependencies(forwardRef(() => CommonService))
  3. export class CatsService {
  4. constructor(commonService) {
  5. this.commonService = commonService;
  6. }
  7. }

Hint The forwardRef() function is imported from the @nestjs/common package.

That covers one side of the relationship. Now let’s do the same with CommonService:

common.service.ts

  1. @Injectable()
  2. export class CommonService {
  3. constructor(
  4. @Inject(forwardRef(() => CatsService))
  5. private catsService: CatsService,
  6. ) {}
  7. }
  1. @Injectable()
  2. @Dependencies(forwardRef(() => CatsService))
  3. export class CommonService {
  4. constructor(catsService) {
  5. this.catsService = catsService;
  6. }
  7. }

Warning The order of instantiation is indeterminate. Make sure your code does not depend on which constructor is called first.

ModuleRef class alternative

An alternative to using forwardRef() is to refactor your code and use the ModuleRef class to retrieve a provider on one side of the (otherwise) circular relationship. Learn more about the ModuleRef utility class here.

Module forward reference

In order to resolve circular dependencies between modules, use the same forwardRef() utility function on both sides of the modules association. For example:

common.module.ts

  1. @Module({
  2. imports: [forwardRef(() => CatsModule)],
  3. })
  4. export class CommonModule {}