A provider tells Angular’s dependency injection system how to produce the value for a token. When a class asks for a dependency, Angular looks up the token, applies the provider’s strategy (useClass, useValue, useFactory, or useExisting) to create or reuse the value, and returns it from the first injector on the lookup path that has a matching provider. Defining a provider well means making three choices: the token that identifies the dependency, the strategy that supplies it, and the injector where it is registered.
What a provider connects
Angular’s guide to defining dependency providers describes two ways to make a service available for injection. Automatic provision places the configuration on the injectable itself, or on a token factory. Manual provision lists providers in a providers array in application configuration, in a route, or on a component or directive. The manual form is where the choices of strategy and scope are visible in your code, so the examples below use it.
As an Amazon Associate I earn from qualifying purchases.
Listing a class in providers is shorthand for an object that makes the two roles explicit:
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated 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 matchproviders: [LocalDataService]
// equivalent to
providers: [{ provide: LocalDataService, useClass: LocalDataService }]
The provide field is the identity consumers request. Everything else in the object describes how Angular obtains the value for that identity.
#1 Best Overall
Tokens: classes, interfaces and InjectionToken
A class constructor can serve as a runtime token because it exists after compilation. A TypeScript interface cannot. Interfaces are erased during compilation, so there is no runtime object Angular could use to look the dependency up, and the injection cannot be resolved. Define an InjectionToken<T> to give an interface-typed value a runtime identity:
import { InjectionToken } from '@angular/core';
export interface DataService {
load(): Promise<string[]>;
}
export const DATA_SERVICE = new InjectionToken<DataService>('DataService');
The same approach covers configuration objects, functions, primitives, and cases where several implementations share one interface. The description string passed to the constructor is for debugging; it does not make the token unique, so the token object itself is what you import and share.
The four provider strategies
Angular’s guide documents these common strategies. Each one answers a different question about where the value comes from.
Recommended Free Tools
Rank #2
useClass: supply an implementation
Use useClass when the token should resolve to an instance of a class. It is the standard way to substitute an implementation, such as a test double or an alternate service, behind a token:
export const appConfig: ApplicationConfig = {
providers: [
{ provide: DATA_SERVICE, useClass: LocalDataService },
],
};
Consumers then receive an instance of LocalDataService when they request DATA_SERVICE.
useValue: supply a fixed value
Use useValue for configuration, URLs, primitives, and plain objects that do not need construction:
Rank #3
export const API_BASE_URL = new InjectionToken<string>('API_BASE_URL');
// in the providers array
{ provide: API_BASE_URL, useValue: 'https://api.example.com' }
useFactory: compute the value
Use useFactory when creation depends on other injected values or on runtime setup. Tokens listed in deps are passed to the factory as arguments, in the same order:
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →{
provide: LOGGER,
useFactory: (config: AppConfig) => new ConsoleLogger(config.logLevel),
deps: [APP_CONFIG],
}
useExisting: create an alias
Use useExisting when one token should point at a provider that is already registered under another token. Both tokens resolve to the same instance within that injector:
providers: [
LocalDataService,
{ provide: DATA_SERVICE, useExisting: LocalDataService },
]
Do not replace this with a second useClass entry. A separate useClass registration creates its own instance, while useExisting preserves the one underlying provider.
Rank #4
Comparing the strategies
| Strategy | What you supply | Instance behavior | Typical use |
|---|---|---|---|
useClass |
A class constructor | Angular creates an instance for the injector that holds the provider | Swapping in a real, mock or alternate implementation |
useValue |
Any static value | Consumers receive the exact value given | Configuration, URLs, primitives, plain objects |
useFactory |
A function, plus a deps list of tokens |
The value the function returns | Creation that depends on other injected values or runtime state |
useExisting |
Another token that is already provided | Same instance as the target provider | An alias that must not create a second object |
Registering several contributions with multi
When several registrations should contribute to one collection, set multi: true. Consumers then receive an array under the shared token, containing one entry per registration:
export const ANALYTICS_PLUGINS =
new InjectionToken<AnalyticsPlugin[]>('ANALYTICS_PLUGINS');
providers: [
{ provide: ANALYTICS_PLUGINS, useClass: PageViewPlugin, multi: true },
{ provide: ANALYTICS_PLUGINS, useClass: ErrorPlugin, multi: true },
]
// consumer receives an AnalyticsPlugin[] containing both instances
private plugins = inject(ANALYTICS_PLUGINS);
Where to register: injector scope
Placement decides which consumers can see a provider and whether a subtree gets its own instance. Angular documents two injector hierarchies, and the hierarchical dependency injection guide explains how they interact.
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 →Environment injectors
Providers in application configuration, and injectables declared with providedIn (for example, providedIn: 'root'), belong to the environment hierarchy. Use this level for dependencies the whole application shares, such as an API client or a logger. In a standalone application, the array passed to bootstrapApplication in main.ts is where application-wide providers are usually declared.
Element injectors
A component’s or directive’s providers array configures its element injector. A value provided there is visible to that element and its descendants. Sibling subtrees and ancestors do not see it, and each instance of the component gets its own copy:
@Component({
selector: 'app-cached-list',
template: '',
providers: [{ provide: DATA_SERVICE, useClass: CachedDataService }],
})
export class CachedListComponent {
private data = inject(DATA_SERVICE); // CachedDataService for this subtree
}
Lookup order
Angular searches from the point where the request is made, moving up the element injector hierarchy first. If the token is not found there, it continues through the environment injector hierarchy. The first matching provider wins, so a component-level provider for a token shadows an application-level provider for the same token within its subtree.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Calling inject()
The inject() function reads a token from the active injector. It only works inside an injection context: during construction of a class that Angular instantiates through DI, in the field initializers of such a class, and in provider factory functions. Elsewhere it throws, so keep it out of ordinary methods:
Free tools Windows power users keep installed
One-click scans. No signup required.
export class ItemsComponent {
private data = inject(DATA_SERVICE); // field initializer: valid
reload() {
const data = inject(DATA_SERVICE); // invalid: a method is not an injection context
}
}
Choosing a provider
Work through these questions in order:
- Is the dependency a concrete class you want to use as its own identity? List the class directly.
- Is the requested type an interface, a primitive, a configuration object, or a function? Create an
InjectionTokenfor it. - Is the value fixed? Use
useValue. - Does creating the value require other injected values? Use
useFactorywith adepslist. - Must two tokens share one instance? Use
useExisting. If each token should get its own instance, useuseClassfor each. - Do several registrations contribute to one collection? Add
multi: true. - Who needs the value? Application-wide dependencies go in environment-level configuration or
providedIn: 'root'. Dependencies that should be isolated to a component subtree go in that component’s or directive’sproviders.
Common mistakes
- Injecting an interface type. Interfaces have no runtime identity. Create an
InjectionTokenand provide under it. - Expecting useExisting to create a new instance. It aliases an existing provider; use
useClasswhen you want a separate object. - Providing a service on one component and expecting another part of the app to see it. The provider is only visible to that element and its descendants. Move it to the environment level if it should be shared.
- Calling inject() in a method. Read the value in a constructor or field initializer and store it.
- Missing registration. If no injector on the lookup path has a provider for the token, Angular fails to resolve it. Register the token at a level that is an ancestor of the consumer.
Versions and scope
The examples follow Angular’s current guides, which describe the standalone application style. Angular APIs and recommended patterns change between releases, so confirm the signatures and configuration locations against the documentation for the version your project uses. The Dependency Injection overview defines a dependency as “any object, value, function, or service that a class requires but does not create itself,” and that definition is the frame for every choice above.
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.




