Dependency Injection in Angular
Estimated study time: 14 minutes. The design pattern that powers how Angular components get their dependencies.
Dependency Injection (DI) is a design pattern where a class receives its dependencies from an external source rather than creating them itself. Angular's DI system is built into the framework's core.
Why Dependency Injection?
Without DI, a component would need to manually instantiate every service it uses — tightly coupling it to specific implementations and making testing painful. With DI, Angular hands a component whatever it declares it needs.
A Basic Example
@Injectable({ providedIn: 'root' })
export class LoggerService {
log(message: string) { console.log('[LOG]', message); }
}
@Component({ selector: 'app-dashboard', templateUrl: './dashboard.component.html' })
export class DashboardComponent {
constructor(private logger: LoggerService) {
this.logger.log('Dashboard initialized');
}
}
Angular sees LoggerService in the constructor and automatically supplies an instance — you never call new LoggerService() yourself.
How the Injector Works
Angular maintains a hierarchical tree of injectors. When a component asks for a dependency, Angular looks for a matching provider starting at the component's own injector, then walks up through its parent injectors until it finds one (or reaches the root).
Providing a Service
// App-wide singleton
@Injectable({ providedIn: 'root' })
export class AuthService {}
// Scoped to a specific module
@NgModule({ providers: [FeatureService] })
export class FeatureModule {}
// Scoped to a specific component and its children
@Component({ providers: [LocalCacheService] })
export class SomeComponent {}
Injection Tokens
For dependencies that aren't classes — like a configuration object or a primitive value — Angular uses InjectionToken to identify what to inject.
export const API_URL = new InjectionToken<string>('API_URL');
providers: [{ provide: API_URL, useValue: 'https://api.example.com' }]
constructor(@Inject(API_URL) private apiUrl: string) {}
providedIn: 'root' for most services — it's tree-shakable, meaning Angular removes it from the final bundle entirely if nothing ever injects it.