Since many Angular applications are standalone these days, we are all used to using different provider functions. The most common ones nearly everyone has seen are provideHttpClient() and provideRouter(). These functions register providers under the hood so that you can use the provided functionalities. If you look at the naming, you could think these are to use in your Components providers: [] array, but in fact, they were created to be used in environment injectors.

What's the problem?

If you start to write your own logger library, you come to a point where you add a provideLogger() function that registers a provider for the configuration.

export function provideLogger(config: Partial<LoggerConfig>) {
  return {
    provide: LoggerConfig,
    useValue: config,

You can use the function in a component or a directive injector without an error. In the long run, this can lead to errors or unexpected behavior in your library. If you design your provideLogger function to configure the logging behavior globally, using it in components with different parameters can cause the logger to behave inconsistently, even though this is not meant to be possible.

The provideLogger function used within the AppComponent

The solution

Angular provides the makeEnvironmentProviders function, which returns an EnvironmentProviders type instead of a provider array. This type wraps the providers to ensure your function is only used in the right place, your bootstrapApplication / ApplicationConfig.
You need the provideLogger implementation to use makeEnvironmentProviders:

import { makeEnvironmentProviders } from "@angular/core";

export function provideLogger(config: Partial<LoggerConfig>) {
  return makeEnvironmentProviders([
      provide: LoggerConfig,
      useValue: config,

Now, if you try to use provideLogger() in a component (or directive), you'll see an error. This error tells you faster that the providers are designed to be used with environment providers and can't be used here.

provideLogger with makeEnvironmentProviders

Tagged in:


Last Update: May 16, 2024