Providers & Injection Tokens
Control how and where a dependency is provided using providers arrays, useValue/useClass, and custom injection tokens.
Providing at Different Levels
providedIn: 'root' gives you one app-wide singleton, but a service (or any dependency) can also be provided at a narrower scope — a specific component and its children — giving that subtree its own separate instance.
Component-Level Providers
Adding a service to a component's own providers array creates a new instance scoped to that component and its descendants, instead of sharing the app-wide singleton.
import { Component } from '@angular/core';import { CartService } from './cart.service';
@Component({ selector: 'app-checkout', standalone: true, providers: [CartService], // a fresh instance, just for this component subtree template: `...`,})export class CheckoutComponent {}Component-level providers are useful when a piece of state should reset each time a component is created — like a multi-step wizard's in-progress form data, which shouldn't persist once the wizard closes.
useValue, useClass, useFactory
Beyond providing a class directly, Angular's provider syntax supports swapping in a plain value, a different class implementing the same interface, or a factory function — useful for configuration and testing.
providers: [ { provide: ApiUrlToken, useValue: 'https://api.example.com' }, { provide: LoggerService, useClass: ConsoleLoggerService }, { provide: FeatureFlagService, useFactory: () => new FeatureFlagService(loadFlagsFromConfig()) },]Injection Tokens
For providing something that isn't a class — a plain configuration object or string — an InjectionToken gives Angular's DI a unique, type-safe key to provide and inject it by.
// api-config.token.tsimport { InjectionToken } from '@angular/core';
export interface ApiConfig { baseUrl: string;}
export const API_CONFIG = new InjectionToken<ApiConfig>('API_CONFIG');// app.config.tsproviders: [ { provide: API_CONFIG, useValue: { baseUrl: 'https://api.example.com' } },]// Using itimport { inject } from '@angular/core';import { API_CONFIG } from './api-config.token';
export class ApiService { private config = inject(API_CONFIG);
getUsers() { return fetch(`${this.config.baseUrl}/users`); }}FAQs
When you want a different implementation for a given token — for example, providing a MockPaymentService in tests wherever a component expects PaymentService.
Configuration is the most common use, but they're also useful whenever you want to inject something Angular can't identify by class alone (like a plain interface or a primitive value).
Summary
Providers control not just what gets injected, but at what scope and with what actual implementation — flexibility that becomes valuable as an app and its test suite grow. Next, you'll use a service to talk to a real backend with HttpClient.