Angular 55 🅰️ Providers and Injection Tokens
In Angular 54, the injector hierarchy was covered: the EnvironmentInjector, the ElementInjector, and the resolution order that walks the tree. This chapter goes deeper into the two pieces that make the hierarchy work: the providers that tell the injector what to create, and the injection tokens that identify what to create. A provider is a recipe — a mapping from a token to a factory or a value or a class. An injection token is the key — the thing that identifies the dependency. The two together are the injector’s vocabulary, and the patterns that use them are what make Angular’s DI flexible. This chapter covers the provider forms in depth, the InjectionToken design, the providedIn scopes, the multi-providers, the APP_INITIALIZER and the ENVIRONMENT_INITIALIZER, the provider factories, and the patterns that make the providers maintainable.
Key point: A provider is an object with a provide key (the token) and one of the useClass, useValue, useFactory, or useExisting keys (the recipe). The injector resolves the token to the recipe and produces the value. The InjectionToken<T> is the typed token, and it is the modern replacement for the string token. The providedIn field on the @Injectable makes the provider tree-shakable, and it scopes the service to the root, a module, or any injector. The multi: true providers make the injector return an array, and they are how the APP_INITIALIZER and the HTTP interceptors compose. The APP_INITIALIZER and the ENVIRONMENT_INITIALIZER are the framework tokens that run the initialization. The provider factories — makeEnvironmentProviders and the EnvironmentProviders type — group the providers for the feature modules.
The provider object
A provider is an object with the provide key and one of the four use* keys. The provide is the token, and the use* is the recipe.
const providers: Provider[] = [
{ provide: Logger, useClass: ConsoleLogger },
{ provide: API_URL, useValue: 'https://api.example.com' },
{
provide: Logger,
useFactory: () => inject(Config).debug ? new ConsoleLogger() : new NullLogger(),
},
{ provide: OldLogger, useExisting: Logger },
];
The four provider objects. The provide is the token, and the use* is the recipe. The Provider type is the union of the four forms and the TypeProvider (a bare class).
Why the provide is required. The provide is the token that the injector maps. The inject(Logger) resolves the Logger token, and the provider’s recipe produces the value. Without the provide, the provider is not a provider.
Why the useClass is the default. The useClass is the default when the provider is a bare class. The providers: [UserService] is the shorthand for providers: [{ provide: UserService, useClass: UserService }].
const shorthand: Provider[] = [UserService];
const explicit: Provider[] = [{ provide: UserService, useClass: UserService }];
The two are the same, and the shorthand is the common.
Why the TypeProvider is the shorthand. The TypeProvider is the type that the providers array accepts. The providers: [UserService] is the TypeProvider, and the explicit object is the ValueProvider or the ClassProvider or the FactoryProvider or the ExistingProvider.
Why the provider can be the EnvironmentProviders. The EnvironmentProviders is the type that the makeEnvironmentProviders returns, and it is the grouped providers for the feature. The providers array of the ApplicationConfig accepts the EnvironmentProviders and the Provider[].
Why the providers are the composable. The providers array can be spread, concatenated, and grouped. The ...featureProviders is the spread, and the makeEnvironmentProviders is the group.
Why the provider object is the plain object. The provider is the plain object, and it is not a class. The provide and the use* are the keys, and the injector reads them. The plain object is the simplicity.
The InjectionToken
The InjectionToken is the typed token for the non-class dependencies. It is the modern replacement for the string token.
export const API_URL = new InjectionToken<string>('API_URL');
export const APP_CONFIG = new InjectionToken<AppConfig>('APP_CONFIG');
export const FEATURE_FLAGS = new InjectionToken<FeatureFlags>('FEATURE_FLAGS');
The InjectionToken<string> is the token, and the inject(API_URL) is the string. The constructor’s argument is the description, and it appears in the error messages.
Why the InjectionToken is the typed. The InjectionToken<T> is the generic, and the inject(API_URL) is the T. The type is the safety, and the token is the key. The string token is the any, and the type is the lost.
Why the InjectionToken is unique. Each new InjectionToken(...) produces a unique token, and the tokens do not collide. The string tokens can collide if the two libraries use the same string, and the InjectionToken is the prevention.
Why the InjectionToken can have the factory. The InjectionToken accepts the options with the providedIn and the factory.
export const API_URL = new InjectionToken<string>('API_URL', {
providedIn: 'root',
factory: () => 'https://api.example.com',
});
The providedIn: 'root' makes the token tree-shakable, and the factory produces the default value. The pattern is the self-provided token.
Why the self-provided token is the default. The self-provided token does not need the providers array entry. The inject(API_URL) resolves the token, and the factory produces the value. The pattern is the convenience, and the test can override the token.
Why the InjectionToken can be the interface. The InjectionToken<SomeInterface> is the token for the interface, and the provide maps it to the implementation.
export const LOGGER = new InjectionToken<Logger>('LOGGER');
const providers: Provider[] = [
{ provide: LOGGER, useClass: ConsoleLogger },
];
The LOGGER is the token, and the ConsoleLogger is the implementation. The interface is the token’s type, and the class is the runtime.
Why the InjectionToken is the modern. The InjectionToken is the Angular 4+ feature, and it replaces the OpaqueToken. The modern code uses the InjectionToken, and the string is the legacy.
Why the InjectionToken should be the const. The token is the const, and it is exported from the module. The pattern is the shared, and the import is the way to use it.
The providedIn scopes
The providedIn field on the @Injectable makes the provider tree-shakable, and it scopes the service. The scopes are 'root', 'any', 'platform', and the module types.
The providedIn: 'root'. The service is the singleton for the application, and it is the tree-shakable.
@Injectable({ providedIn: 'root' })
export class UserService {}
The service is created when the first inject(UserService) is called, and the same instance is returned for the application’s lifetime. The bundler can tree-shake the service when it is not used.
Why the 'root' is the singleton. The root injector is the application’s injector, and the service is the single instance. The pattern is the application-wide, and the use is the common.
The providedIn: 'any'. The service is the new instance for each injector.
@Injectable({ providedIn: 'any' })
export class ScopedService {}
Each injector — the root, the lazy module, the component — gets its own instance. The pattern is the per-injector, and the use is the rare.
Why the 'any' is the per-injector. The service is the new instance for each injector, and the instances are the separate. The pattern is the scoped, and the use is the rare.
The providedIn: SomeModule. The service is the module’s scope.
@Injectable({ providedIn: SomeModule })
export class ModuleService {}
The service is the singleton within the module, and the lazy module’s instance is the different. The pattern is the module’s scope, and the use is the feature.
Why the module scope is the feature. The service is the feature’s, and the feature’s components share the instance. The pattern is the scope, and the use is the lazy-loaded feature.
The providedIn: 'platform'. The service is the platform’s scope.
@Injectable({ providedIn: 'platform' })
export class PlatformService {}
The service is the singleton across the applications on the platform. The pattern is the multi-application, and the use is the rare.
Why the providedIn is the tree-shakable. The providedIn makes the provider the tree-shakable, and the bundler can remove the unused. The providers array is not the tree-shakable, and the service is the included.
The multi-providers
The multi: true provider makes the injector return an array. Each provider adds one element, and the injector collects them.
const providers: Provider[] = [
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true },
];
const interceptors = inject(HTTP_INTERCEPTORS); // the array
The HTTP_INTERCEPTORS is the token, and the two providers add the two interceptors. The inject(HTTP_INTERCEPTORS) returns the array of the two.
Why the multi: true is the collection. The multiple providers with the same token and the multi: true collect into the array. The pattern is the plugin, and the use is the interceptor, the validator, and the initializer.
Why the multi is the composition. The multi-providers compose, and the consumer receives the array. The pattern is the open-closed, and the feature can add the element without the consumer’s change.
The APP_INITIALIZER. The APP_INITIALIZER is the token for the application initialization.
export const appConfig: ApplicationConfig = {
providers: [
{
provide: APP_INITIALIZER,
useFactory: () => () => loadConfig(),
multi: true,
},
],
};
The APP_INITIALIZER is the multi-token, and the factory returns the function that runs at the initialization. The application waits for the function’s return value (or the Promise) before the bootstrap.
Why the APP_INITIALIZER is the startup. The initializers run before the application renders, and the pattern is the config load, the auth check, and the feature flag fetch. The pattern is the startup, and the use is the common.
The ENVIRONMENT_INITIALIZER. The ENVIRONMENT_INITIALIZER is the token for the environment’s initialization.
const providers: EnvironmentProviders = makeEnvironmentProviders([
{
provide: ENVIRONMENT_INITIALIZER,
useValue: () => {
const service = inject(SomeService);
service.init();
},
multi: true,
},
]);
The ENVIRONMENT_INITIALIZER runs when the environment injector is created, and the inject() is the valid inside. The pattern is the feature’s initialization, and the use is the lazy module.
Why the ENVIRONMENT_INITIALIZER is the feature’s. The initializer runs when the environment injector is created, which is when the lazy module is loaded. The pattern is the feature’s setup, and the use is the lazy module’s registration.
The multi: true and the order. The multi-providers are collected in the order they appear, and the consumer receives them in the order. The pattern is the order, and the use is the priority.
Why the multi is the common. The multi: true is the common in the Angular’s framework tokens — the HTTP_INTERCEPTORS, the APP_INITIALIZER, the ENVIRONMENT_INITIALIZER, the ROUTES, and the others. The pattern is the framework’s, and the use is the plugin.
The makeEnvironmentProviders and the EnvironmentProviders
The makeEnvironmentProviders groups the providers into the EnvironmentProviders, and the type ensures that the providers are the environment’s.
export function provideFeature(): EnvironmentProviders {
return makeEnvironmentProviders([
FeatureService,
{ provide: FEATURE_CONFIG, useValue: defaultConfig },
{
provide: ENVIRONMENT_INITIALIZER,
useValue: () => inject(FeatureService).init(),
multi: true,
},
]);
}
The provideFeature is the function that returns the EnvironmentProviders, and the consumer uses the providers: [provideFeature()].
Why the EnvironmentProviders is the type. The EnvironmentProviders is the opaque type that the makeEnvironmentProviders returns. The type ensures that the providers are the environment’s, and the providers array of the ApplicationConfig accepts them.
Why the makeEnvironmentProviders is the grouping. The function groups the related providers, and the consumer uses the single function. The pattern is the feature’s providers, and the use is the library.
Why the EnvironmentProviders cannot be spread. The EnvironmentProviders is the opaque, and the spread is the error. The pattern is the group, and the use is the single function.
Why the EnvironmentProviders is the modern. The EnvironmentProviders is the Angular 15+ feature, and it replaces the ModuleWithProviders. The modern code uses the makeEnvironmentProviders, and the legacy is the module.
Why the library uses the EnvironmentProviders. The library exports the provideX function, and the consumer uses it. The pattern is the encapsulation, and the use is the library’s API.
Why the EnvironmentProviders is the tree-shakable. The makeEnvironmentProviders is the tree-shakable when the function is the pure. The bundler can remove the unused, and the pattern is the modern.
The provider factories
The provider factory is the function that produces the provider, and it is the way to parameterize the provider.
export function provideLogger(config: LoggerConfig): Provider {
return {
provide: LOGGER,
useFactory: () => config.debug ? new ConsoleLogger() : new NullLogger(),
};
}
The provideLogger takes the config and returns the provider. The consumer uses the providers: [provideLogger({ debug: true })].
Why the provider factory is the parameterized. The factory takes the argument, and the provider uses it. The pattern is the config, and the use is the library.
Why the provider factory is the function. The function is the provideX, and the consumer calls it. The pattern is the API, and the use is the library’s.
Why the provider factory is the composable. The factory can return the multiple providers, and the consumer uses the array.
export function provideFeature(config: FeatureConfig): Provider[] {
return [
{ provide: FEATURE_CONFIG, useValue: config },
FeatureService,
];
}
The provideFeature returns the array, and the consumer uses the providers: [...provideFeature(config)]. The pattern is the composition, and the use is the feature.
Why the provider factory is the testable. The factory is the pure function, and the test can assert the returned provider. The pattern is the test, and the use is the library’s.
Why the provider factory is the modern. The provideX function is the Angular 15+ pattern, and it replaces the ModuleWithProviders. The modern code uses the provideX, and the legacy is the module.
Why the provider factory is the naming. The convention is the provideX, where the X is the feature. The pattern is the name, and the use is the consistent.
Why the provider factory is the alternative to the providedIn. The providedIn is the automatic, and the provideX is the explicit. The providedIn is for the self-contained, and the provideX is for the configurable. The two are the choice, and the use is the design.
Complete Example Session
import {
Injectable, InjectionToken, Provider, EnvironmentProviders,
makeEnvironmentProviders, inject, APP_INITIALIZER,
ENVIRONMENT_INITIALIZER, ApplicationConfig,
} from '@angular/core';
// ============================================
// PART 1: THE PROVIDER OBJECTS
// ============================================
interface Logger {
log(message: string): void;
}
class ConsoleLogger implements Logger {
log(message: string): void { console.log(message); }
}
const providers: Provider[] = [
{ provide: Logger, useClass: ConsoleLogger },
];
// ============================================
// PART 2: THE INJECTION TOKEN
// ============================================
export const API_URL = new InjectionToken<string>('API_URL');
export const APP_CONFIG = new InjectionToken<AppConfig>('APP_CONFIG');
// ============================================
// PART 3: THE SELF-PROVIDED TOKEN
// ============================================
export const DEFAULT_TIMEOUT = new InjectionToken<number>('DEFAULT_TIMEOUT', {
providedIn: 'root',
factory: () => 30000,
});
// ============================================
// PART 4: THE USE FACTORY
// ============================================
const loggerProvider: Provider = {
provide: Logger,
useFactory: () => inject(APP_CONFIG).debug ? new ConsoleLogger() : new NullLogger(),
};
// ============================================
// PART 5: THE USE EXISTING
// ============================================
const aliasProviders: Provider[] = [
{ provide: Logger, useClass: ConsoleLogger },
{ provide: OldLogger, useExisting: Logger },
];
// ============================================
// PART 6: THE MULTI PROVIDERS
// ============================================
const interceptorProviders: Provider[] = [
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true },
];
const interceptors = inject(HTTP_INTERCEPTORS); // the array
// ============================================
// PART 7: THE APP INITIALIZER
// ============================================
export const appConfig: ApplicationConfig = {
providers: [
{
provide: APP_INITIALIZER,
useFactory: () => () => loadConfig(),
multi: true,
},
],
};
// ============================================
// PART 8: THE ENVIRONMENT INITIALIZER
// ============================================
export function provideFeature(): EnvironmentProviders {
return makeEnvironmentProviders([
FeatureService,
{
provide: ENVIRONMENT_INITIALIZER,
useValue: () => inject(FeatureService).init(),
multi: true,
},
]);
}
// ============================================
// PART 9: THE PROVIDER FACTORY
// ============================================
export function provideLogger(config: LoggerConfig): Provider {
return {
provide: LOGGER,
useFactory: () => config.debug ? new ConsoleLogger() : new NullLogger(),
};
}
export function provideFeatureWithConfig(config: FeatureConfig): Provider[] {
return [
{ provide: FEATURE_CONFIG, useValue: config },
FeatureService,
];
}
// ============================================
// PART 10: WHAT NOT TO DO
// ============================================
// Don't use a string token in new code
// { provide: 'API_URL', useValue: '...' } // use InjectionToken
// Don't forget the multi: true
// { provide: APP_INITIALIZER, useFactory: () => ... } // the array is not
// Don't spread the EnvironmentProviders
// providers: [...provideFeature()] // ❌ the EnvironmentProviders is opaque
// Don't forget the inject() in the factory
// { useFactory: (config) => ... } // the config is undefined
// Don't use the providedIn for the configurable
// The providedIn is the automatic; the provideX is the configurable.
// Don't forget the return type
// function provideFeature() { return makeEnvironmentProviders([...]); }
// the return type is the EnvironmentProviders
The ten parts cover the provider objects, the injection token, the self-provided token, the use factory, the use existing, the multi-providers, the APP_INITIALIZER, the ENVIRONMENT_INITIALIZER, the provider factory, and the anti-patterns.
Quick Reference
The Provider Forms
| Form | Purpose |
|---|---|
{ provide, useClass } | The class instance |
{ provide, useValue } | The value |
{ provide, useFactory } | The factory |
{ provide, useExisting } | The alias |
SomeClass | The shorthand for useClass |
The InjectionToken
| Form | Purpose |
|---|---|
new InjectionToken<T>('desc') | The token |
new InjectionToken<T>('desc', { providedIn, factory }) | The self-provided |
The providedIn Scopes
| Value | Scope |
|---|---|
'root' | The application singleton |
'any' | The per-injector |
'platform' | The platform |
SomeModule | The module’s scope |
The Multi-Providers
| Token | Purpose |
|---|---|
HTTP_INTERCEPTORS | The HTTP interceptors |
APP_INITIALIZER | The app startup |
ENVIRONMENT_INITIALIZER | The env setup |
ROUTES | The routes |
The Provider Factories
| Function | Returns |
|---|---|
provideLogger(config) | The Provider |
provideFeature(config) | The Provider[] |
provideFeature() | The EnvironmentProviders |
makeEnvironmentProviders([...]) | The EnvironmentProviders |
The Framework Tokens
| Token | Purpose |
|---|---|
APP_INITIALIZER | The app startup |
ENVIRONMENT_INITIALIZER | The env setup |
HTTP_INTERCEPTORS | The HTTP interceptors |
APP_BOOTSTRAP_LISTENER | The bootstrap listener |
Best Practices
✅ Do This:
// Use the InjectionToken for the non-class
export const API_URL = new InjectionToken<string>('API_URL'); // ✅
// Use the providedIn: 'root' for the singleton
@Injectable({ providedIn: 'root' })
export class UserService {} // ✅
// Use the multi: true for the collection
{ provide: APP_INITIALIZER, useFactory: () => ..., multi: true } // ✅
// Use the makeEnvironmentProviders for the feature
export function provideFeature(): EnvironmentProviders {
return makeEnvironmentProviders([...]);
} // ✅
// Use the provider factory for the configurable
export function provideLogger(config: LoggerConfig): Provider { ... } // ✅
// Use the useExisting for the alias
{ provide: OldLogger, useExisting: Logger } // ✅
// Use the inject() in the factory
useFactory: () => inject(Config).debug ? new ConsoleLogger() : new NullLogger() // ✅
❌ Don’t Do This:
// Don't use a string token
{ provide: 'API_URL', useValue: '...' } // ⚠️
// Don't forget the multi: true
{ provide: APP_INITIALIZER, useFactory: () => ... } // ⚠️
// Don't spread the EnvironmentProviders
providers: [...provideFeature()] // ❌ // ⚠️
// Don't forget the inject() in the factory
{ useFactory: (config) => ... } // the config is undefined // ⚠️
// Don't use the providedIn for the configurable
// The providedIn is the automatic. // ⚠️
// Don't forget the return type
function provideFeature() { return makeEnvironmentProviders([...]); } // ⚠️
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
| The string token | The collision | Use InjectionToken |
The missing multi | The array is not | Add multi: true |
The spread of the EnvironmentProviders | The opaque type | Use the function |
The missing inject() | The undefined | Use inject() |
The providedIn for the config | The not configurable | Use the provideX |
| The missing return type | The inference | Annotate it |
| The wrong scope | The wrong instance | Check the providedIn |
Real-World Examples
1. The provider object
{ provide: Logger, useClass: ConsoleLogger }
2. The InjectionToken
export const API_URL = new InjectionToken<string>('API_URL');
3. The self-provided token
new InjectionToken<number>('TIMEOUT', { providedIn: 'root', factory: () => 30000 })
4. The useFactory
{ provide: Logger, useFactory: () => inject(Config).debug ? ... : ... }
5. The useExisting
{ provide: OldLogger, useExisting: Logger }
6. The multi-provider
{ provide: APP_INITIALIZER, useFactory: () => ..., multi: true }
7. The makeEnvironmentProviders
export function provideFeature(): EnvironmentProviders {
return makeEnvironmentProviders([...]);
}
8. The provider factory
export function provideLogger(config: LoggerConfig): Provider { ... }
9. The ENVIRONMENT_INITIALIZER
{ provide: ENVIRONMENT_INITIALIZER, useValue: () => inject(S).init(), multi: true }
10. The APP_INITIALIZER
{ provide: APP_INITIALIZER, useFactory: () => () => loadConfig(), multi: true }
Visual: The Provider Forms
┌──────────────────────────────────────────────────────────┐
│ useClass │
│ { provide: Logger, useClass: ConsoleLogger } │
│ The injector creates the instance. │
│ │
│ useValue │
│ { provide: API_URL, useValue: 'https://api' } │
│ The injector returns the value. │
│ │
│ useFactory │
│ { provide: Logger, useFactory: () => ... } │
│ The injector calls the factory. │
│ │
│ useExisting │
│ { provide: OldLogger, useExisting: Logger } │
│ The injector returns the alias. │
│ │
└──────────────────────────────────────────────────────────┘
Visual: The InjectionToken
┌──────────────────────────────────────────────────────────┐
│ export const API_URL = new InjectionToken<string>('API_URL');│
│ │ │
│ │ the token │
│ │ the type is the string │
│ ▼ │
│ inject(API_URL) → string │
│ │
│ THE SELF-PROVIDED │
│ │
│ export const TIMEOUT = new InjectionToken<number>('TIMEOUT', {│
│ providedIn: 'root', │
│ factory: () => 30000, │
│ }); │
│ │
│ inject(TIMEOUT) → 30000 │
│ The token provides itself. │
│ │
└──────────────────────────────────────────────────────────┘
Visual: The providedIn Scopes
┌──────────────────────────────────────────────────────────┐
│ 'root' │
│ The application singleton. │
│ The tree-shakable. │
│ │
│ 'any' │
│ The per-injector instance. │
│ The not tree-shakable. │
│ │
│ 'platform' │
│ The platform singleton. │
│ The shared across the apps. │
│ │
│ SomeModule │
│ The module's scope. │
│ The per-module instance. │
│ │
└──────────────────────────────────────────────────────────┘
Visual: The Multi-Providers
┌──────────────────────────────────────────────────────────┐
│ { provide: HTTP_INTERCEPTORS, useClass: Auth, multi: true }│
│ { provide: HTTP_INTERCEPTORS, useClass: Log, multi: true } │
│ │ │
│ ▼ │
│ inject(HTTP_INTERCEPTORS) → [Auth, Log] │
│ │
│ The multiple providers collect into the array. │
│ The order is the declaration order. │
│ │
│ THE FRAMEWORK TOKENS │
│ │
│ APP_INITIALIZER → the startup functions │
│ ENVIRONMENT_INITIALIZER → the env setup functions │
│ HTTP_INTERCEPTORS → the interceptors │
│ ROUTES → the routes │
│ │
└──────────────────────────────────────────────────────────┘
Visual: The Provider Factory
┌──────────────────────────────────────────────────────────┐
│ export function provideLogger(config: LoggerConfig): Provider {│
│ return { │
│ provide: LOGGER, │
│ useFactory: () => config.debug ? new ConsoleLogger() : new NullLogger(),│
│ }; │
│ } │
│ │
│ THE CONSUMER │
│ providers: [provideLogger({ debug: true })] │
│ │
│ THE FEATURE │
│ export function provideFeature(): EnvironmentProviders {│
│ return makeEnvironmentProviders([...]); │
│ } │
│ │
│ providers: [provideFeature()] │
│ │
│ The factory is the parameterized, and the function is │
│ the API. │
│ │
└──────────────────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
| Provider | The recipe for the injector |
provide | The token |
useClass | The class instance |
useValue | The value |
useFactory | The factory |
useExisting | The alias |
InjectionToken<T> | The typed token |
providedIn: 'root' | The tree-shakable singleton |
multi: true | The collection |
APP_INITIALIZER | The app startup |
ENVIRONMENT_INITIALIZER | The env setup |
makeEnvironmentProviders | The feature group |
Key takeaways:
- A provider is the object with the
provideand theuse*— theprovideis the token, and theuse*is the recipe, and the four types are theuseClass, theuseValue, theuseFactory, and theuseExisting - The
InjectionTokenis the typed token for the non-class dependencies — theInjectionToken<T>is the generic, and it replaces the string token - The self-provided token has the
providedInand thefactory— it does not need theprovidersarray entry, and the test can override it - The
providedInscopes are'root','any','platform', and the module — the'root'is the tree-shakable singleton, and the'any'is the per-injector - The
multi: truemakes the injector return the array — the multiple providers with the same token collect, and the order is the declaration - The
APP_INITIALIZERand theENVIRONMENT_INITIALIZERare the framework tokens — the first runs before the bootstrap, and the second when the environment injector is created - The
makeEnvironmentProvidersgroups the providers — theEnvironmentProvidersis the opaque type, and theprovideXfunction is the API - The provider factory parameterizes the providers — the
provideLogger(config)returns the provider with the config, and theprovideFeature(config)returns the array - The
provideXfunction is the modern pattern — it replaces theModuleWithProviders, and the library exports the function - The
provideXand theprovidedInare the choice — theprovidedInis the automatic, and theprovideXis the configurable
Remember: The providers and the injection tokens are the injector’s vocabulary. The provider is the recipe, the token is the key, and the four use* types are the forms. The InjectionToken is the typed, the providedIn is the scope, and the multi: true is the collection. The provideX function is the modern pattern, and the makeEnvironmentProviders is the group. The providers are the configuration, and the tokens are the identity.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!