Have you heard about Hack Frontend Community?Join us on Telegram!

Injector Hierarchy in Angular: How Dependency Injection Works

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.

By continuing to use the platform, you accept the terms of the Privacy Policy and the use of cookies.