How to Get Environment Specific Configuration at Runtime in Angular
Tags: initialization, environment, configuration, api
Published: 2023-07-15 01:16:16

---
title: How to Get Environment Specific Configuration at Runtime in Angular
published: true
date: 2023-07-14 17:01:11 UTC
tags: initialization,environment,configuration,api
canonical_url: https://medium.com/@seanhaddock_60973/how-to-get-environment-specific-configuration-at-runtime-in-angular-9c4497aa11d3
---

![](https://cdn-images-1.medium.com/max/1024/0*W9ZD0-svUmOtictg)
_Photo by Rima Kruciene on Unsplash_

In this post, I’m going to show you one way to retrieve environment specific configuration information dynamically with Angular.

### What are the Options for Accessing Environment Specific Config Settings?

You have at least two options for accessing environment specific configuration information in Angular. You can set static values in environment files or you can retrieve values at runtime from a config file or API. Let’s discuss each in turn.

### Environment Files

If you know your target environment at build time, you can use environment files to store configuration information. You can define a file for each environment that you need to target, and the values in the appropriate file will be included based on the --configuration flag that is passed to the build command. I really like environment files and they would be my first choice. But in my scenario, I do not know at build time, in what environment the code will be run, because the same build gets deployed to multiple environments. So I need to retrieve the info at runtime.

### Config File or API

For the config file approach, you would deploy a JSON file in the assets folder of your application, and then you would need some process outside of Angular to swap out the file based on the environment.

Most of the time, the API host is the config info you need in the first place, so the API option might not be helpful. But in my case, my Angular app is hosted by a legacy app with its own API that I can access with a relative URL, and it has the config info I need (which includes a _different_ API host, which is what I need to get).

Both approaches have the same implementation. Let’s discuss that next.

### Accessing App Configuration at Runtime

#### The InjectionToken

Create the interface for your app configuration in app.config.ts (I like putting it in the root, next to app.module.ts). This represents the shape of your configuration information.

```
export interface AppConfig {
  apiHost: string;
}
```

Next, create an InjectionToken with that interface, that will represent your app config object, and allow you to inject it where it’s needed. This can go in app.config.ts as well.

```
import { InjectionToken } from '@angular/core';

export const APP_CONFIG = new InjectionToken<AppConfig>('app.config');
```

> An InjectionToken is a kind of placeholder you can put in code with the expectation that it will be populated at runtime. It’s a basic DI mechanism and is often used to represent interfaces or strings. So you can say, I need this interface or string in this function, but I’m going to decide at runtime what the actual value will be, or let the users of my code decide what it will be. Using different values for testing is also a common use case.

#### Retrieving the Config Values

Next we need to retrieve the app config values. You’ll most likely want to make sure that you have loaded the config before your application runs. For this, Angular has provided the APP\_INITIALIZER InjectionToken.

First, in app.module.ts, above the @NgModule decorator, add the following constant and function:

```
const MY_APP_CONFIG: AppConfig = {
  apiHost: '',
};
function initializeAppFactory(httpClient: HttpClient): () => Observable<AppConfig> {
  return () =>
    httpClient.get<AppConfig>('/api/config/getconfig').pipe(
      tap((config) =>
        Object.assign(MY_APP_CONFIG, {
          ...config,
          apiHost: `https://${config.apiHost}`,
        })
      )
    );
}
```

Replace MY\_APP\_CONFIG with an appropriate name for your app, and replace the URL in the httpClient.get function with the URL to your API or JSON file in the assets folder. The purpose of this function is to retrieve your config values and put them in the MY\_APP\_CONFIG constant which will be used later.

Now we need to tell Angular to call this function when the app initializes by adding this to the providers array of the NgModule object:

```
{ 
  provide: APP_INITIALIZER, 
  useFactory: initializeAppFactory, 
  deps: [HttpClient], 
  multi: true 
}
```

Here we are telling Angular that when it’s looking for APP\_INITIALIZER values, it should use our function. The useFactory property (as opposed to useValue or useClass), let’s Angular know to expect a function. We tell Angular that our function is going to need HttpClient, and that there may be other values provided for APP\_INITIALIZER elsewhere (multi: true).

Finally, we need to tell Angular to use the actual config info (now stored in MY\_APP\_CONFIG), whenever APP\_CONFIG is wanted, by adding this line to the providers array of the NgModule object:

```
{ provide: APP_CONFIG, useValue: MY_APP_CONFIG }
```

Now, in your app, you can use the retrieved config info by injecting the APP\_CONFIG token (remember we just told Angular what to use whenever this token is requested):

```
appConfig = inject(APP_CONFIG);
...
url = this.appConfig.apiHost
...
```

That’s it! Now you can retrieve app config values dynamically at runtime, and have those values available before any of your application code runs.

#### Full app.config.ts

```
import { InjectionToken } from '@angular/core';

export interface AppConfig {
  apiHost: string;
}

export const APP_CONFIG = new InjectionToken<AppConfig>('app.config');
```

#### Full app.module.ts

```
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { HttpClient } from '@angular/common/http';
import { Observable, tap } from 'rxjs';
import { APP_CONFIG, AppConfig } from './app.config';

const MY_APP_CONFIG: AppConfig = {
  apiHost: '',
};
function initializeAppFactory(httpClient: HttpClient): () => Observable<AppConfig> {
  return () =>
    httpClient.get<AppConfig>('/api/config/getconfig').pipe(
      tap((config) =>
        Object.assign(MY_APP_CONFIG, {
          ...config,
          apiHost: `https://${config.apiHost}`,
        })
      )
    );
}

@NgModule({
  declarations: [AppComponent],
  imports: [],
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: initializeAppFactory,
      deps: [HttpClient],
      multi: false,
    },
    { provide: APP_CONFIG, useValue: MY_APP_CONFIG },
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}
```

### Bibliography

- [https://angular.io/guide/build#configuring-application-environments](https://angular.io/guide/build#configuring-application-environments)
- [https://angular.io/api/core/APP\_INITIALIZER](https://angular.io/api/core/APP_INITIALIZER)
- [https://angular.io/api/core/InjectionToken](https://angular.io/api/core/InjectionToken)
- [https://angular.io/guide/dependency-injection-providers#using-an-injectiontoken-object](https://angular.io/guide/dependency-injection-providers#using-an-injectiontoken-object)