Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The shorthand you will see most often is a class name placed directly in a providers array:

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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:

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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.

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:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Lookup 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.Support on Ko-Fi

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choosing a provider: a checklist

  1. Is the requested thing a class? If yes and it needs no substitution, a class in providers is enough. If not, create an InjectionToken.
  2. Is it an interface or a non-class value? Use an InjectionToken<T> as the key.
  3. Is the value fixed? Use useValue.
  4. Does creation depend on other injected values? Use useFactory and call inject() inside it.
  5. Should this token share an instance with another token? Use useExisting. Use useClass if you want a separate instance.
  6. Do several registrations contribute to one list? Add multi: true.
  7. 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.

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.