Hack Frontend Community

Injector Hierarchy in Angular

What is Injector Hierarchy in Angular?

In Angular dependency injection (Dependency Injection, DI) is built on injector hierarchy, where dependencies can be available:

  • Globally
  • Only within module
  • Only in component
  • Only in specific directive or pipe

Angular creates injector tree, similar to component tree. Each component can have own injector, inherited from parent.

Injector Hierarchy Levels

Global Level — @Injectable({ providedIn: 'root' })

  • Service is created once for entire application.
  • Available everywhere without need to specify in providers.
@Injectable({ providedIn: 'root' })
export class LoggerService {}

Used by default for singleton services.

Module Level (in @NgModule.providers)

  • Service is available only within specified module.
  • If module is imported into other modules — behavior may differ.
@NgModule({
  providers: [AuthService]
})
export class AuthModule {}

Good for limited access and lazy-loaded modules.

Component Level (in @Component.providers)

  • Service is created separately for each component instance.
  • Suitable for local state, independent from other components.
@Component({
  selector: 'app-cart',
  templateUrl: './cart.component.html',
  providers: [CartService]
})
export class CartComponent {}

For each component usage new instance of service will be created.

Directive/Pipe Level (@Directive.providers)

  • Similarly to components — service is created locally, inside element where directive is applied.
@Directive({
  selector: '[highlight]',
  providers: [HighlightService]
})
export class HighlightDirective {}

How Angular Searches Dependencies

When Angular injects dependency, it:

  • First looks in component's local injector.
  • If not found — searches in parent injector.
  • And so on up to root injector (root).
  • If dependency not found — throws error.

Example: nested components and different injectors

@Component({
  selector: 'parent',
  providers: [SharedService],
  template: `<child></child>`
})
export class ParentComponent {}

@Component({
  selector: 'child',
  template: `...`
})
export class ChildComponent {
  constructor(shared: SharedService) {} // will get instance from parent
}

If SharedService is not specified in child, it will be inherited from parent.