---
title: "NG0200: dependência circular na injeção de dependências"
description: "O que o NG0200 Circular Dependency in DI quer dizer, como ler a cadeia A -> B -> A que o Angular imprime, as três formas que produzem o ciclo (serviços mútuos, uma facade que injeta o próprio serviço, um token que resolve pra si mesmo), e os consertos em ordem, da reestruturação até o forwardRef como último recurso."
deck: "`NG0200: Circular Dependency in DI` quer dizer que um provider depende, direta ou indiretamente, de si mesmo. A [descrição oficial](https://angular.dev/errors/NG0200) é exata: existe um ciclo quando uma dependência de um serviço depende do próprio serviço, como o `UserService` precisando do `EmployeeService` enquanto o `EmployeeService` precisa do `UserService`. Leia a cadeia que o Angular imprime, ache onde o laço se fecha, e deixe a dependência num sentido só. Fonte: [angular.dev/errors/NG0200](https://angular.dev/errors/NG0200)."
author: "André Ramos"
url: "https://andreramos.dev/pt/angular/angular-ng0200-circular-dependency-di/"
lang: "pt-BR"
type: "article"
---

# NG0200: dependência circular na injeção de dependências

> `NG0200: Circular Dependency in DI` quer dizer que um provider depende, direta ou indiretamente, de si mesmo. A [descrição oficial](https://angular.dev/errors/NG0200) é exata: existe um ciclo quando uma dependência de um serviço depende do próprio serviço, como o `UserService` precisando do `EmployeeService` enquanto o `EmployeeService` precisa do `UserService`. Leia a cadeia que o Angular imprime, ache onde o laço se fecha, e deixe a dependência num sentido só. Fonte: [angular.dev/errors/NG0200](https://angular.dev/errors/NG0200).

## Leia a cadeia antes de mexer em qualquer coisa

O NG0200 não é um mistério, é um mapa. O runtime não consegue construir um provider porque construir ele exige construir ele mesmo primeiro, então para e imprime o ciclo que percorreu. A doc coloca de forma direta: existe uma dependência cíclica quando uma dependência de um serviço depende, direta ou indiretamente, do próprio serviço.

Leia a cadeia como uma stack trace, porque é isso que ela é. `A -> B -> A` quer dizer que o injector pediu o `A`, o `A` pediu o `B`, e o `B` pediu o `A` de novo antes do `A` terminar de construir. O primeiro e o último token são o mesmo, e essa repetição é o laço. O conserto mora na aresta dessa cadeia que você consegue deixar num sentido só sem trapacear. A orientação que a página dá é usar a call stack pra achar onde o ciclo está, e então quebrar o laço removendo ou refatorando as dependências pra elas não dependerem uma da outra.

## As três formas que isso costuma tomar

A maioria dos casos de NG0200 cai em uma de três formas, e nomear a forma já te diz o conserto. A primeira são dois serviços injetando um ao outro, aquele caso clássico do `UserService` e do `EmployeeService` que a doc usa. A segunda é uma facade que injeta um serviço que, em algum ponto da própria lista de dependências, injeta a facade de volta: o ciclo é mais longo, então se esconde melhor, mas a cadeia impressa ainda fecha no mesmo token. A terceira é um token cuja factory ou alias `useExisting` resolve pra si mesmo, o que cria o laço sem nenhuma simetria óbvia entre duas classes.

A forma importa porque a cura muda. Serviços mútuos pedem que um dos dois sentidos seja apagado. Um ciclo de facade quase sempre quer dizer que uma peça compartilhada está morando no lugar errado. Já um token que aponta pra si mesmo costuma ser um erro de fiação no provider, não um problema de design, e ler o array de `providers` resolve mais rápido do que ler as classes.

| Forma do ciclo | Como a cadeia aparece | Primeiro conserto a tentar |
|---|---|---|
| Dois serviços se injetam | UserService -> EmployeeService -> UserService | Apague um dos sentidos; deixe a dependência fluir num só. |
| Facade injeta um serviço que injeta a facade | Facade -> OrdersService -> Facade | Extraia a peça que os dois precisam pra um terceiro serviço. |
| Token resolve pra si mesmo | TOKEN -> factory -> TOKEN | Leia o array de providers; o useExisting ou useFactory aponta pro próprio token. |

## O conserto, em ordem

Reestruture primeiro. Se o `A` precisa do `B` e o `B` precisa do `A`, em geral uma dessas duas dependências é opcional ou pertence a outro lugar. Escolha a menos essencial pra construção e remova, pra o grafo virar uma linha em vez de um círculo. É esse o conserto que a doc aponta, e é o único que muda o design em vez do sintoma.

Quando as duas metades precisam mesmo de uma coisa compartilhada, extraia essa coisa pra um terceiro serviço que não depende de nenhuma das duas. O `A` e o `B` passam a depender do `C`, e o `C` não depende de nenhum dos dois, então o ciclo não se forma. É essa a jogada pra quase todo ciclo de facade que eu vejo: a facade e o serviço estavam os dois indo atrás de um estado ou de um helper que queria a própria casa.

Quando a dependência só é necessária na hora da chamada, e não na hora da construção, não injete ela no construtor de jeito nenhum. Passe como argumento de método, ou leia através de um signal que o outro lado já é dono. Uma dependência que a classe segura pra um método só não precisa ser dependência de construtor, e tirar ela da construção a remove do ciclo que o injector está tentando resolver.

*O ciclo, e a quebra extraindo um terceiro serviço*

```ts
// NG0200: cada serviço pede o outro na hora da construção,
// então nenhum consegue terminar de construir primeiro.
@Injectable({ providedIn: 'root' })
export class UserService {
  private readonly employees = inject(EmployeeService); // -> EmployeeService
}

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

// Quebra: a busca compartilhada que os dois precisavam vai pra um
// terceiro serviço que não depende de nenhum. O grafo virou linha.
@Injectable({ providedIn: 'root' })
export class DirectoryStore {
  // o estado ou helper que UserService e EmployeeService dividiam
}

@Injectable({ providedIn: 'root' })
export class UserService {
  private readonly directory = inject(DirectoryStore); // num sentido só
}

@Injectable({ providedIn: 'root' })
export class EmployeeService {
  private readonly directory = inject(DirectoryStore); // num sentido só
}
```

## Por que o forwardRef é último recurso, não conserto

Busque NG0200 e o `forwardRef` aparece rápido, porque ele faz o erro sumir. O que ele de fato faz é estreito: a doc descreve ele como um jeito de se referir a uma referência que está declarada mas ainda não definida, e foi feito pra problemas de ordem de token, uma classe usada antes da declaração ser avaliada, e imports circulares entre componentes standalone. Ele adia o momento em que a referência resolve. Ele não remove a dependência entre os dois providers.

Então, se o ciclo é uma dependência real de runtime, em que o `A` precisa de um `B` já construído e o `B` precisa de um `A` já construído, o `forwardRef` só muda quando a busca acontece, e não se o laço existe. Eu trataria o `forwardRef` como um cheiro, não como conserto: ele está certo quando o problema é ordem ou uma circularidade de import standalone, e é um curativo quando o problema são dois serviços que nem deviam depender um do outro pra começar. Use quando você confirmou que a dependência é mesmo uma referência pra frente, e reestruture quando não confirmou.

*forwardRef: certo pra ordem, errado como remendo de design*

```ts
// Legítimo: o token é referenciado antes da declaração dele ser
// avaliada, então adiamos a busca. Aqui o forwardRef se justifica.
@Injectable({ providedIn: 'root' })
export class DoorService {
  private readonly lock = inject(forwardRef(() => LockService));
}

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

// Mau uso: embrulhar uma dependência mútua real em forwardRef só adia
// a resolução. O design continua um ciclo; reestruture no lugar.
providers: [
  { provide: UserService, useClass: UserService },
  { provide: EmployeeService, useExisting: forwardRef(() => UserService) }, // cheiro
]
```

## Confirme a quebra, não presuma

Depois de reestruturar, prove que o ciclo foi embora em vez de confiar que foi. Builde, rode, e faça um grep nos serviços que você mexeu atrás da injeção que fechava o laço, porque um ciclo de facade pode se reformar no momento em que alguém adiciona a referência de volta sem ler a cadeia.

*Ache quem ainda injeta pela aresta antiga*

```bash
# Rebuild e deixe o injector te dizer que o ciclo foi embora
ng build

# Grep nos dois serviços atrás da injeção que fechava o laço
rg -n "inject\(UserService\)|inject\(EmployeeService\)" src/app
```

## Artefato reaproveitável: Quebrando um ciclo de dependência NG0200

- Leia a cadeia impressa como uma stack: o token que aparece primeiro e por último é onde o laço fecha.
- Nomeie a forma: dois serviços se injetando, uma facade injetando um serviço que a injeta de volta, ou um token que resolve pra si mesmo.
- Reestruture primeiro: apague o sentido menos essencial pra a dependência fluir num só.
- Se as duas metades precisam de uma coisa compartilhada, extraia pra um terceiro serviço que não depende de nenhuma.
- Se a dependência só é usada na hora da chamada, passe como argumento de método ou leia através de um signal em vez de injetar.
- Use forwardRef só pra referências pra frente de verdade (ordem, circularidade de import standalone), nunca pra encobrir uma dependência mútua real.
- Builde de novo e faça um grep nos serviços que você mexeu pra confirmar que a referência de volta foi mesmo embora.

## Perguntas frequentes

### O que quer dizer o NG0200 Circular Dependency in DI?

Quer dizer que um provider depende de si mesmo através de uma cadeia. A doc define como dependência cíclica: uma dependência de um serviço depende, direta ou indiretamente, do próprio serviço, como o UserService precisando do EmployeeService enquanto o EmployeeService precisa do UserService. O injector não consegue construir nenhum dos dois primeiro.

### Como leio a cadeia A -> B -> A que o Angular imprime?

Leia como uma stack trace. O injector pediu o primeiro token, esse token pediu o próximo, e assim por diante até a cadeia voltar pra um token que já estava sendo construído. O token repetido marca o laço. O conserto é a aresta dessa cadeia que você consegue deixar num sentido só.

### O forwardRef conserta uma dependência circular?

Ele muda quando a referência resolve, não se a dependência existe. A doc limita o forwardRef a referências declaradas mas ainda não definidas, incluindo circularidades de import standalone. Pra dois serviços que precisam mesmo um do outro na hora da construção, o forwardRef só adia a resolução; o design continua um ciclo e deveria ser reestruturado.

### Como quebro uma facade e um serviço que dependem um do outro?

Extraia a peça que os dois vão buscar pra um terceiro serviço que não depende de nenhum. A facade e o serviço passam a depender desse terceiro serviço num sentido só, então o ciclo não se forma. Isso resolve os ciclos mais longos e escondidos que a cadeia impressa ainda fecha no mesmo token.

## Fontes consultadas

- 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

## Leia também

- [NG0203: por que o inject() falha fora do contexto de injeção](https://andreramos.dev/pt/angular/angular-ng0203-inject-outside-injection-context/)
- [Facade Pattern no Angular: quando o componente sabe demais](https://andreramos.dev/pt/angular/facade-pattern-in-angular/)
- [Strategy Pattern no Angular: trocando regras sem espalhar switches](https://andreramos.dev/pt/angular/strategy-pattern-in-angular/)
