Angular's DI is hierarchical: injectors form a tree that mirrors the component/module tree. When a component requests a dependency, Angular walks up the injector tree until it finds a provider — which controls whether you get a shared singleton or a separate instance per component.
The injector hierarchy
Root injector (app-wide) ← providedIn: 'root' lives here (one singleton)
└─ Module/Route injectors
└─ Component injector ← providers: [...] in @Component
└─ Child component injector
A lookup starts at the requesting component and bubbles up to the root. The provider found wins.
