The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
Angular resolves a dependency from the nearest provider it can reach. For a component or directive, that usually means checking the current and ancestor element injectors first, then searching the environment injector hierarchy. This model explains why a component can get its own service instance, why a local provider can override a root provider, and where to look when Angular reports a missing provider.
Angular’s injector hierarchies at a glance
Modern Angular applications primarily use two hierarchies. They serve different purposes: one associates providers with the application or an environment, while the other associates them with elements in the component tree.
| Hierarchy | Where providers are configured | What it means for scope |
|---|---|---|
| EnvironmentInjector | providedIn metadata, an InjectionToken factory, or ApplicationConfig.providers; additional environment injectors can also be created. |
Provides application- or environment-level dependencies. The root EnvironmentInjector is created during bootstrap; additional environments can be used for router scopes or dynamically loaded components. |
| ElementInjector | A component or directive’s providers or, for a component, viewProviders. |
Associated with a DOM element. Angular creates these injectors implicitly, and they are empty unless providers are configured. Components and directives on the same element share an injector. |
| ModuleInjector | NgModule.providers and providers reachable through its imports. |
Relevant to NgModule-based applications. Lazy-loaded NgModules can create child ModuleInjector hierarchies. |
The platform injector is above the root injector, and the NullInjector is the final fallback. If no provider is found, resolution fails there unless the request is optional. See Angular’s guide to hierarchical injectors for the hierarchy details.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchHow Angular searches for a dependency
For a request made by a component or directive, Angular searches from the requesting element outward. It checks the current ElementInjector, then its ancestors. If no provider matches, Angular returns to the requesting element and searches the EnvironmentInjector ancestry. In an NgModule-based app, the ModuleInjector hierarchy is also involved.
#1 Best Overall
- Check the current element. A provider on the requesting component or directive’s element is considered first.
- Check ancestor elements. Angular walks up the element-injector tree until it finds a matching provider or reaches the end of that path.
- Check environment scope. If the element path has no match, Angular searches the relevant EnvironmentInjector ancestry (and the ModuleInjector hierarchy in NgModule-based applications).
- Fail at the NullInjector if still unresolved. An ordinary request then produces a missing-provider error; an optional request can instead return
null.
The first provider Angular finds wins. A provider on a nearer component can therefore take precedence over a provider configured at application level. This is intentional: it lets a subtree customize a dependency without changing what other parts of the application receive.
Choose a provider scope that matches the instance you need
Application-wide sharing
Use a root-level provider when the service should be shared across the application and have application-level scope. A service can declare providedIn: 'root', or the application can configure providers through ApplicationConfig.providers. Angular notes that the providedIn approach supports tree-shaking of unused services. Application configuration can override a service’s providedIn: 'root' default.
Rank #2
Environment or route scope
Additional EnvironmentInjectors allow providers to be scoped to an environment, including router scopes or dynamically loaded components. Choose this when the dependency should not simply be treated as globally shared, but avoid assuming that every route or dynamically loaded component automatically creates a distinct scope: the relevant environment injector must be configured for that scope.
Free tools Windows power users keep installed
One-click scans. No signup required.
Component-subtree isolation
Configure a service in a component’s providers when that component and its descendants should resolve a component-associated instance. The instance belongs to that component’s ElementInjector and is destroyed when the component is destroyed. This is useful for state that should be isolated between component instances or shared only within a subtree. A provider on a directive also configures its element injector.
Rank #3
Values that are not classes
Use an InjectionToken for dependencies such as configuration objects, functions, or primitive values that do not have a class type to use as the token. A token can supply a factory, while providers can also be configured manually in component, directive, route, or application configuration.
Use resolution modifiers to control the search
Modifiers change what the default ancestor search does: whether it may return no result, where it begins, or how far it can travel. Angular documents four common modifiers:
Rank #4
optionalchanges missing-provider behavior: Angular returnsnullinstead of failing when no provider is found.selfrestricts the lookup to the current injector. Use it when the dependency must be provided locally rather than inherited.skipSelfstarts lookup at the parent injector, bypassing a provider on the current injector.hostlimits how far lookup can travel at the host boundary, subject to Angular’s view and content visibility rules.
These modifiers are especially useful when a provider deliberately delegates to an ancestor, a component requires a local dependency, or an optional integration should not make the requesting code fail when absent. The precise lookup boundary can depend on the component’s view/content relationship; consult Angular’s hierarchical dependency injection guide when applying host.
Debug a missing provider or an unexpected duplicate
Angular’s troubleshooting guide describes the practical path as the current element injector, parent element injectors, the environment injector, and finally NullInjector. For a NullInjectorError, verify both that a provider exists and that the requesting component can reach it.
- Confirm the token is provided. Check the service’s injectable declaration, token factory, or relevant
providersarray. - Check the requesting component’s path. A provider can exist but still be outside the requester’s reachable element or environment hierarchy.
- Look for a nearer override. A local provider may intentionally replace the application-level instance.
- Investigate duplicate “singleton” instances. Inspect component-level
providers; registering a service there associates it with that component’s injector rather than relying only on the root instance. - Visualize the hierarchy. Angular DevTools includes an injector tree inspector that shows injector levels and their providers.
For Angular’s full troubleshooting guidance, see Debugging and troubleshooting DI. For provider configuration patterns, see Defining dependency providers.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

