Free tools Windows power users keep installed
One-click scans. No signup required.
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
A provider tells Angular’s dependency injection (DI) system which value to supply when something asks for a given token. Which provider strategy you pick (useClass, useValue, useFactory, or useExisting) controls how that value is created. Where you register the provider controls which parts of the app can receive it. Getting those three choices right, the token, the strategy, and the injector location, is most of what defining providers involves.
What a provider does
A dependency is any object, value, function, or service that a class requires but does not create itself, as Angular’s Dependency Injection overview puts it. A provider is the instruction that answers the question “what do I hand over when this is requested?”
Every provider has two parts. The token is the lookup key that consumers ask for. The provider strategy describes how Angular obtains the value for that key. Angular’s guide to defining dependency providers describes two ways to make a service available: automatic provision, where the injectable itself declares how it is provided, and manual provision, where you list providers in an array in application configuration, a route, a component, or a directive.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →The shorthand you will see most often is a class name placed directly in a providers array:
#1 Best Overall
providers: [LocalDataService]
That is equivalent to the longer object form:
providers: [{ provide: LocalDataService, useClass: LocalDataService }]
The object form is the one to learn, because it separates the identity consumers request (provide) from the way Angular supplies it (the use... property). Every other pattern in this article is a variation on that split.
Choosing a token
A token must exist at runtime, because Angular uses it as a lookup key. Class constructors already do. Other values need a token object created explicitly.
Why a TypeScript interface cannot be a token
Interfaces are erased during compilation, so no runtime object remains for Angular to look up. Suppose you define an interface DataService with a concrete implementation LocalDataService. The interface gives you a compile-time type, but nothing you can pass as a token. Angular needs a value to match, and there isn’t one.
Using InjectionToken
An InjectionToken<T> gives an interface-typed value, a configuration object, a function, or a primitive a runtime identity. The generic parameter keeps the type information for consumers:
import { InjectionToken } from '@angular/core';
export interface DataService {
load(): Promise<string[]>;
}
export const DATA_SERVICE = new InjectionToken<DataService>('DataService');
You then register an implementation under that token:
Rank #2
providers: [
{ provide: DATA_SERVICE, useClass: LocalDataService }
]
Consumers ask for DATA_SERVICE rather than the interface. This is also the normal pattern when several implementations share one interface, because the token, not the interface, decides which one is supplied.
The four provider strategies
Angular’s documented common strategies differ in how the value is produced and whether the requested token is a separate identity.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →| Strategy | Where the value comes from | Typical use | Instance behavior |
|---|---|---|---|
useClass |
An implementation class Angular instantiates | Swapping in a mock, a test double, or an alternate service for a token | Creates an instance of the named class under the requested token |
useValue |
A static value you write in the provider | Configuration, a URL, a primitive, or a plain object | The value you supply is what consumers receive |
useFactory |
A function that Angular calls to create the value | Creation that depends on other injected values or runtime setup | The factory’s return value is what consumers receive |
useExisting |
A provider already registered under a different token | An alias, so two tokens reach the same underlying provider | Both tokens resolve to the same instance |
useClass: substitute an implementation
Use useClass when the token should resolve to a class other than the one named in it. This is how you replace a real data service with a fake in tests or in a demo configuration, while components keep asking for the same token.
useValue: supply a fixed value
Use useValue for values that are known when you write the provider:
export const API_BASE_URL = new InjectionToken<string>('API_BASE_URL');
providers: [
{ provide: API_BASE_URL, useValue: 'https://api.example.com' }
]
Because the value is not created by a class or function, there is nothing to instantiate. Use it for configuration you already have.
Rank #3
useFactory: create the value at injection time
Use useFactory when the value depends on something else. The factory can read other tokens through inject() (covered below), which is the usual way to build an object from configuration:
providers: [
{
provide: DATA_SERVICE,
useFactory: () => {
const baseUrl = inject(API_BASE_URL);
return new HttpDataService(baseUrl);
}
}
]
Angular calls factory functions within an injection context, which is why inject() is allowed there.
useExisting: alias one token to another
Use useExisting when you want a second token to point at a provider that already exists. It does not create a second instance:
providers: [
LocalDataService,
{ provide: DATA_SERVICE, useExisting: LocalDataService }
]
Here, a consumer of DATA_SERVICE and a consumer of LocalDataService share one object. This is the key difference from useClass, which would make DATA_SERVICE its own instance of the class.
Collecting contributions with multi: true
When several registrations should contribute to one collection, mark each provider with multi: true. Consumers then receive an array under the shared token:
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 matchRank #4
export const VALIDATORS = new InjectionToken<Validator[]>('VALIDATORS');
providers: [
{ provide: VALIDATORS, useClass: RequiredValidator, multi: true },
{ provide: VALIDATORS, useClass: LengthValidator, multi: true }
]
Without multi: true, the second registration would replace the first rather than add to it.
Where to register a provider
Placement determines who can see the value. Angular documents two injector hierarchies, described in its hierarchical dependency injection guide.
The environment injector
Providers configured in application configuration, and in injectable declarations, belong to the environment hierarchy. Use it for services that the whole application should share, such as an authentication or logging service that has no reason to differ between parts of the page.
The element injector
A component or directive’s providers array configures its element injector. The value is then available to that element and its descendants, and separate component subtrees can each receive their own instance. Use this when a service holds state that should be isolated to one part of the UI, such as a form’s draft state.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsLookup order
When a consumer requests a token, Angular checks the element injector hierarchy first, starting at the request location and moving upward. If the token is not found there, Angular checks the environment injector hierarchy.
| Where the provider is declared | Injector hierarchy | Who can receive it |
|---|---|---|
| Application configuration or an injectable declaration | Environment | Consumers throughout the application that reach the environment injector |
A component or directive providers array |
Element | That element and its descendants; it takes precedence over an environment provider for the same token |
A consequence follows from that order. If a component provides a token that also exists at the application level, consumers inside that component get the nearer value, and the application-level value is used everywhere else. Do not describe a service as a single app-wide instance unless you have confirmed its providers are only declared at the environment level.
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 injector that is active at the moment it runs. Angular limits where it may be called to an injection context: the constructor of a class instantiated by DI, the field initializers of such a class, and provider factory functions. Calling it in ordinary code, such as an event handler or a callback that runs later, is not a supported way to look up dependencies. The inject() API reference defines these restrictions.
export class ReportComponent {
private readonly data = inject(DATA_SERVICE);
}
If you see a runtime error that mentions an injection context, move the inject() call into a field initializer or a constructor, or resolve the dependency in a factory instead.
Recommended Free Tools
Choosing a provider: a checklist
- Is the requested thing a class? If yes and it needs no substitution, a class in
providersis enough. If not, create anInjectionToken. - Is it an interface or a non-class value? Use an
InjectionToken<T>as the key. - Is the value fixed? Use
useValue. - Does creation depend on other injected values? Use
useFactoryand callinject()inside it. - Should this token share an instance with another token? Use
useExisting. UseuseClassif you want a separate instance. - Do several registrations contribute to one list? Add
multi: true. - Who should see it? Application-wide services go in environment-level configuration. State that belongs to one component subtree goes in that component’s or directive’s
providers.
Version and verification
The behavior described here follows Angular’s official documentation as it stood when this article was prepared in October 2026. Angular APIs and recommended patterns change between releases, so check the examples against the documentation for the Angular version your project uses, and confirm the names and signatures in the API reference before relying on them in production code.
The concepts that remain stable across versions are the separation of token and strategy, the difference between an alias and a new instance, and the rule that provider placement determines lookup. Those are the parts to get right first.
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.

