Skip to main content

Cercular Dependency In NestJS

Firefly (from Honkai Star Rail) staring at you
Last updated: July 25, 2024

#Understanding Circular Dependency in NestJS

In the project I’m currently working on, I encountered a small issue.

I had two modules dependent on each other, each using the service of the other. Nest threw a Circular Dependency Exception, and the solution was to use the forwardRef() method.

#Let’s Understand the Error and Solution

First off, Nest works with Dependency Injection (DI), which is a way to achieve the Dependency Inversion Principle from the SOLID principles.

There are several ways to inject dependencies into your class, such as injecting the dependency either in the class constructor or in one of the class methods.

Nest follows the constructor strategy for this. However, Nest introduced a new feature to implement DI and solve a major problem in applications.

Your app isn’t just a single module; it has multiple modules, each with a large number of providers and possibly multiple controllers. This large number might lead you to create multiple objects of the same class for injection, resulting in storage waste.

#So How Did Nest Solve This Problem?

Nest introduced a new concept called the IoC (Inversion of Control) container.

When your application starts, all the classes in your app, along with their metadata, get registered in the IoC container.

This container does two things:

  1. Resolves all the classes and determines all the dependencies for each class.
  2. Initializes all the dependencies.

Thus, you have a single source of truth for all your dependencies.

#What’s the Cause of Circular Dependency, and Why Is It a Problem?

We mentioned that Nest has two phases: the resolution phase, where it identifies all the classes and their dependencies, and the initialization phase, where it initializes all the classes.

The problem arises when Nest starts resolving a particular class and finds that it has a dependency on another class. Nest then tries to resolve this dependency, only to find that the second class, in turn, depends on the first class. Nest ends up in a loop, causing a known issue called a deadlock.

#How Do We Solve This Problem?

The solution is to delay the resolution of these two classes until all other classes have been resolved and instantiated. Then, we can resolve the dependencies of these two classes.

This is exactly what the forwardRef() method does. When Nest encounters this method, it defers the resolution process for the modules that use it. It acknowledges the dependency relationship but delays the resolution process until everything else is done, then completes the resolution process for these modules.

Lastly, it’s worth mentioning that circular dependencies can occur at different levels, not just at the module level but also at the service level. However, the concept remains the same.

For a deeper dive, check out the resource below:

📜 Offecial NestJS Docs

📜 Article from Digital Ocean