Angular's Hierarchical Dependency Injection

Angular's DI is a tree of injectors mirroring your components. When a component needs a service, Angular walks up the tree to find the first provider. Use it to scope services to UI branches, but beware: providing at a component level creates a new instance.
WHY IT EXISTS Large applications need a way to manage dependencies without creating a single, global bucket of services. Hierarchical dependency injection provides a structured, scalable way to provide and consume services, enabling modularity, state encapsulation, and lazy loading.
THE MENTAL MODEL Imagine your app's component hierarchy as a tree. Angular's DI system creates a parallel tree of 'injectors'. When a component asks for a service, Angular starts a search: it looks at its own injector, then its parent's, then its grandparent's, and so on, all the way to the root. The first injector in the chain that knows how to provide the service wins. It's like scope resolution for variables in a programming language.
HOW IT WORKS When you declare a dependency in a component's constructor (e.g., constructor(private auth: AuthService)), Angular's injector is responsible for providing an instance. The search begins at the component's own injector. If no provider is registered there (in the component's providers array), the request is forwarded to the parent component's injector. This process continues up the tree until it reaches the application's root injector. If no provider is found anywhere in the hierarchy, Angular throws a NullInjectorError.
WHEN TO USE IT Use hierarchical injection to scope service instances. For example, provide a service at a parent route component to have all child routes share a single instance of that service, creating state that is isolated to that specific feature area. It's also useful for providing different configurations of the same service to different parts of your application.
WHEN NOT TO USE IT Avoid providing services at the component level if you need a true, application-wide singleton. For services that should have only one instance across the entire app, like an authentication service or a user settings service, always use the providedIn: 'root' syntax on the @Injectable() decorator. This ensures it's registered with the root injector and is globally available.
ONE CANONICAL EXAMPLE A 'smart' container component might be responsible for a list of items. You can provide a ListStateService directly on this container component. All child 'dumb' presentational components can then inject this service to get data or trigger actions. When the user navigates away and the container component is destroyed, the ListStateService instance and its state are automatically cleaned up with it.
Read the original → angular.dev
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.