---
title: "NG0200 Circular Dependency in DI: Reading the Chain and Breaking It"
description: "What NG0200 Circular Dependency in DI means, how to read the A -> B -> A chain Angular prints, the three causes that produce it (mutual services, a facade that injects its own service, a token that resolves to itself), and the fixes ranked from restructuring down to forwardRef as a last resort."
deck: "`NG0200: Circular Dependency in DI` means a provider depends, directly or indirectly, on itself. The [official description](https://angular.dev/errors/NG0200) is exact: a cycle exists when a dependency of a service depends on the service itself, like `UserService` needing `EmployeeService` while `EmployeeService` needs `UserService`. Read the printed chain, find where the loop closes, and make the dependency one-directional. Source: [angular.dev/errors/NG0200](https://angular.dev/errors/NG0200)."
author: "André Ramos"
url: "https://andreramos.dev/angular/angular-ng0200-circular-dependency-di/"
lang: "en"
type: "article"
---

# NG0200 Circular Dependency in DI: Reading the Chain and Breaking It

> `NG0200: Circular Dependency in DI` means a provider depends, directly or indirectly, on itself. The [official description](https://angular.dev/errors/NG0200) is exact: a cycle exists when a dependency of a service depends on the service itself, like `UserService` needing `EmployeeService` while `EmployeeService` needs `UserService`. Read the printed chain, find where the loop closes, and make the dependency one-directional. Source: [angular.dev/errors/NG0200](https://angular.dev/errors/NG0200).

## Read the chain before you touch anything

NG0200 is not a mystery; it is a map. The runtime cannot build a provider because building it requires building itself first, so it stops and prints the cycle it walked. The docs put it plainly: a cyclic dependency exists when a dependency of a service directly or indirectly depends on the service itself.

Read the chain like a stack trace, because it is one. `A -> B -> A` means the injector asked for `A`, `A` asked for `B`, and `B` asked for `A` again before `A` finished constructing. The first and last token are the same, and that repetition is the loop. The fix lives at whichever edge in that chain you can make one-directional without faking it. The guidance the page gives is to use the call stack to find where the cycle exists, then break the loop by removing or refactoring the dependencies so they are not reliant on one another.

## The three shapes this actually takes

Most NG0200 reports collapse into one of three shapes, and naming the shape tells you the fix. The first is two services injecting each other, the textbook `UserService` and `EmployeeService` case from the docs. The second is a facade that injects a service which, somewhere down its own dependency list, injects the facade back: the cycle is longer, so it hides better, but the printed chain still closes on the same token. The third is a token whose factory or `useExisting` alias resolves to itself, which produces the loop without any obvious two-class symmetry.

The shape matters because the cure differs. Mutual services want one of the two directions deleted. A facade cycle usually means a shared piece is living in the wrong place. A self-referential token is almost always a provider wiring mistake, not a design problem, and reading the `providers` array fixes it faster than reading the classes.

| Shape of the cycle | What the chain looks like | First fix to try |
|---|---|---|
| Two services inject each other | UserService -> EmployeeService -> UserService | Delete one direction; make the dependency flow one way. |
| Facade injects a service that injects the facade | Facade -> OrdersService -> Facade | Extract the shared piece both need into a third service. |
| Token resolves to itself | TOKEN -> factory -> TOKEN | Read the providers array; the useExisting or useFactory points back at its own token. |

## The fix, ranked

Restructure first. If `A` needs `B` and `B` needs `A`, one of those two needs is usually optional or belongs elsewhere. Pick the dependency that is less essential to construction and remove it, so the graph becomes a line instead of a circle. This is the fix the docs point at, and it is the only one that changes the design rather than the symptom.

When both halves genuinely need a shared thing, extract that shared thing into a third service that neither depends back on. `A` and `B` both depend on `C`, and `C` depends on neither, so the cycle cannot form. This is the move for almost every facade cycle I see: the facade and the service were both reaching for state or a helper that wanted its own home.

When the dependency is only needed at call time, not at construction time, do not inject it into the constructor at all. Pass it as a method argument, or read it through a signal the other side already owns. A dependency the class holds for one method does not need to be a constructor dependency, and moving it out of construction removes it from the cycle the injector is trying to resolve.

*The cycle, and the break by extracting a third service*

```ts
// NG0200: each service asks for the other at construction time,
// so neither can finish building first.
@Injectable({ providedIn: 'root' })
export class UserService {
  private readonly employees = inject(EmployeeService); // -> EmployeeService
}

@Injectable({ providedIn: 'root' })
export class EmployeeService {
  private readonly users = inject(UserService); // -> UserService -> cycle
}

// Break it: the shared lookup both needed moves into a third service
// that depends on neither. The graph is now a line, not a circle.
@Injectable({ providedIn: 'root' })
export class DirectoryStore {
  // the state or helper UserService and EmployeeService were sharing
}

@Injectable({ providedIn: 'root' })
export class UserService {
  private readonly directory = inject(DirectoryStore); // one-directional
}

@Injectable({ providedIn: 'root' })
export class EmployeeService {
  private readonly directory = inject(DirectoryStore); // one-directional
}
```

## Why forwardRef is the last resort, not the fix

Search NG0200 and `forwardRef` shows up fast, because it makes the error disappear. What it actually does is narrow: the docs describe it as a way to refer to a reference that is declared but not yet defined, and it is built for token-ordering problems, a class used before its declaration is evaluated, and circular imports between standalone components. It defers when the reference resolves. It does not remove the dependency between the two providers.

So if the cycle is a real runtime dependency, where `A` needs a constructed `B` and `B` needs a constructed `A`, `forwardRef` only changes when the lookup happens, not whether the loop exists. I would treat `forwardRef` as a smell, not a fix: it is correct when the problem is ordering or a standalone-import circularity, and it is a bandage when the problem is two services that should not depend on each other in the first place. Reach for it when you have confirmed the dependency is genuinely a forward reference, and restructure when you have not.

*forwardRef: right for ordering, wrong as a design patch*

```ts
// Legitimate: the token is referenced before its declaration is
// evaluated, so we defer the lookup. forwardRef earns its place here.
@Injectable({ providedIn: 'root' })
export class DoorService {
  private readonly lock = inject(forwardRef(() => LockService));
}

@Injectable({ providedIn: 'root' })
export class LockService {}

// Misuse: wrapping a real mutual dependency in forwardRef just delays
// the resolution. The design is still a cycle; restructure instead.
providers: [
  { provide: UserService, useClass: UserService },
  { provide: EmployeeService, useExisting: forwardRef(() => UserService) }, // smell
]
```

## Confirm the break, do not assume it

Once you have restructured, prove the cycle is gone instead of trusting that it is. Build, run, and grep the touched services for the injection that used to close the loop, because a facade cycle can re-form the moment someone adds the back-reference again without reading the chain.

*Find who still injects across the old edge*

```bash
# Rebuild and let the injector tell you the cycle is gone
ng build

# Grep the two services for the injection that used to close the loop
rg -n "inject\(UserService\)|inject\(EmployeeService\)" src/app
```

## Reusable artifact: Breaking an NG0200 dependency cycle

- Read the printed chain as a stack: the token that appears first and last is where the loop closes.
- Name the shape: two services injecting each other, a facade injecting a service that injects it back, or a token that resolves to itself.
- Restructure first: delete the less-essential direction so the dependency flows one way.
- If both halves need a shared thing, extract it into a third service that depends on neither.
- If the dependency is only used at call time, pass it as a method argument or read it through a signal instead of injecting it.
- Use forwardRef only for true forward references (ordering, standalone-import circularity), never to paper over a real mutual dependency.
- Rebuild and grep the touched services to confirm the back-reference is actually gone.

## FAQ

### What does NG0200 Circular Dependency in DI mean?

It means a provider depends on itself through a chain. The docs define it as a cyclic dependency: a dependency of a service directly or indirectly depends on the service itself, such as UserService needing EmployeeService while EmployeeService needs UserService. The injector cannot construct either one first.

### How do I read the A -> B -> A chain Angular prints?

Read it like a stack trace. The injector asked for the first token, that token asked for the next, and so on until the chain returns to a token already being built. The repeated token marks the loop. The fix is whichever edge in that chain you can make one-directional.

### Does forwardRef fix a circular dependency?

It changes when the reference resolves, not whether the dependency exists. The docs scope forwardRef to references declared but not yet defined, including standalone-import circularities. For two services that genuinely need each other at construction time, forwardRef only delays resolution; the design is still a cycle and should be restructured.

### How do I break a facade and service that depend on each other?

Extract the piece both reach for into a third service that depends on neither. The facade and the service then both depend on that third service in one direction, so the cycle cannot form. This fixes the longer, hidden cycles that the printed chain still closes on the same token.

## Sources checked

- https://angular.dev/errors/NG0200
- https://angular.dev/guide/di
- https://angular.dev/guide/di/creating-and-using-services
- https://angular.dev/guide/di/defining-dependency-providers
- https://angular.dev/api/core/forwardRef
- https://angular.dev/api/core/inject

## Related

- [NG0203: Why inject() Fails Outside an Injection Context](https://andreramos.dev/angular/angular-ng0203-inject-outside-injection-context/)
- [Facade Pattern in Angular: When Components Know Too Much](https://andreramos.dev/angular/facade-pattern-in-angular/)
- [Strategy Pattern in Angular: Swapping Rules Without Spreading Switches](https://andreramos.dev/angular/strategy-pattern-in-angular/)
