How does APP_INITIALIZER work? So what do you need to know about dynamic configuration in Angular?
Tags: angular, javascript, frontend, programming
Published: 2023-07-07 08:26:29


## How does APP_INITIALIZER work? So what do you need to know about dynamic configuration in Angular?

When we develop an application designed to run on multiple environments, we have to decide how to provide a configuration of appropriate variables depending on those environments

## **TLDR; 📕**

* *environment.ts* is not the best way to provide an environment configuration

* do not introduce environmental configuration in build-time

* Special injection token called *APP_INITIALIZER* is used for convenient and effective external configuration providing

* I’ve prepared for you the minimal example which solves this problem by using *APP_INITIALIZER*. You can find it on [StackBlitz](https://stackblitz.com/edit/angular-configuration-with-app-initializer)


## First round ❓

The simplest example of an environmental variable is API configuration. Commonly, we use a different URL depending on target environment. For instance:

* dev: https://yourdomain.dev.org/api/resources

* test: https://yourdomain.test.org/api/resources

* prod: https://yourdomain.prod.org/api/resources

In many Angular projects that I have seen, this problem has been solved by using analogous files provided by the Angular framework: *environment.dev.ts*, *environment.test.ts* and *environment.prod.ts*.

These files for our example would look like this
{% gist https://gist.github.com/marcinmilewicz/4f4a20d255df6ccc0e9f750490dd4e5b.js %}
It cannot be said that this approach is very bad or does nor meet the assumptions made. However, look what happens if you choose this way to keep your variables and want to complete the full cycle of application delivery to production.

 1. If everything works fine locally, the application is built on the development environment using the environment.dev.ts file

 2. If everything works fine in the development environment, we can promote it to the test environment. In order for the application to run in the test environment, the application must be rebuilt using the environment.test.ts file this time

 3. If the application has been tested in the test environment and is ready for production, we have to take the same steps. So we need to rebuild the application again using environment.prod.ts

Please note one fact. The application must be built three times (**!!!**) before it goes from the developer’s hand to the production environment.

### The first conclusions that arise are: 👈

* If you want to deliver a small change to production, you have to repeat the same building process several times, which will significantly extend the delivery time.

* You can never be sure that a tested artifact from the dev environment or test will build correctly on the prod environment

Based on these conclusions and my own experience, I can safely and honestly tell you that environment.ts files are not a good place to hold most types of configuration. More precisely:

Certain configuration types should not be shipped when building an artifact. Storing environment-dependent variables in Angular’s environment.ts is the anti-pattern. Unfortunately, common anti-pattern.

So if you choose not to hold your configuration in environment.ts, what can you do?

## Round 2 — APP_INITIALIZER approach 💪

Angular’s Injection Token APP_INITIALIZER comes with great help, thanks to which you can introduce additional initialization functions to your application. This functionality of the Angular framework ensures that the provided functions are executed when an application is started, while an application is still being initialized. These functions return a Promise object and an Angular’s app will not be initialized until it is being executed.

Is is a proper way to pass the configuration?

### Of course! Even in the official Angular framework documentation, you can read: 📕
>  You can, for example, create a factory function that loads language data or an external configuration, and provide that function to the [APP_INITIALIZER](https://angular.io/api/core/APP_INITIALIZER) token. That way, the function is executed during the application bootstrap process, and the needed data is available on startup.
>  [Follow me](https://twitter.com/marcin_milewicz) on Twitter if you want to be updated about new great Angular and frontend stuff! *😄*

### Runtime configuration in practice

Firstly, we need a file to hold configuration details in, and it will not be part of JavaScript artifacts which are built when *ng build* is executed. This configuration file should be downloaded on demand when the application is initialized.
{% gist https://gist.github.com/marcinmilewicz/ae7365c331c52143dce73a8b7c271557.js %}
for the following assumed configuration model.
{% gist https://gist.github.com/marcinmilewicz/3a1917dd942030b6fb03f404e9aef8ce.js %}
We also need a service that has the responsibility to download the configuration and make it available while the application is running.
{% gist https://gist.github.com/marcinmilewicz/bba5df9598e66f869464d9d980ccfd05.js %}
The last step is to use the above method with the *APP_INITIALIZER* token. It is used in the providers section for a specific *NgModule*.

It’s worth to consider creating a separate module dedicated to fetching configuration instead of adding the following code to the main app.module.ts
{% gist https://gist.github.com/marcinmilewicz/c37a75bd302f60059454eaf2f9e8c389.js %}
The *loadConfiguration* function is provided with the *useFactory* parameter. The function itself looks like this
{% gist https://gist.github.com/marcinmilewicz/35f388de986d8c5578bb737f78cbc5c0.js %}
By following the steps above, we ensure the following behavior for our application

* when the application is started, the *loadConfiguration* from the *ConfigurationLoader* instance is run and it starts downloading the configuration from */assets/config/configuration.json*

* the application waits until the configuration is loaded from */assets/config/configuration.json*

* Finally, the application is initialized and the configuration is available through *getConfiguration* method of *ConfigurationLoader* instance

The magic is that the configuration placed in the *assets* directory is not taken into account at the time of building. You can modify the contents of the *assets* directory at any time without rebuilding the app. So the scheme for delivering the application to production now looks like this

 1. If everything works fine locally, the application is built on the development environment and the */assets/config/configuration.json* file is delivered externally

 2. If everything works fine in the development environment, the application is promoted to the test environment. In order to run the application in the test environment, we take the artifact already built and replace the */assets/config/configuration.json* file, which this time contains the configuration specific to the test environment

 3. If the application is passed the tests in the test environment and is ready to go to the production, we take the same artifact again, push it to the prod environment and replace the analogous configuration file */assets/config/configuration.json* for the prod environment.

Wow! By using *APP_INITIALIZER* and runtime configuration approach, you are able to limit the process of building the application in the entire delivery cycle to only one time! Frankly speaking, this one time is the maximum number of times according to the best practices. You also ensured that your built artifact on the initial environment is equal to a single byte with what is placed in the final environment.

If you want to see how this solution works, I have prepared a live example on [***StackBlitz](https://stackblitz.com/edit/angular-configuration-with-app-initializer)*** for you.

![](https://cdn-images-1.medium.com/max/6000/1*3XUVentW0YdEgmpTcEL7Fw.png)

## Summary 📕

* *environment.ts* is **not the best way** to provide an environment configuration in Angular ecosystem. We can safely name it as anti-pattern.

* **do not introduce** an environment configuration which is runtime-dependant

* Injection Token — APP_INITIALIZER is used for **convenient and effective** external configuration delivery in Angular ecosystem.

* I have prepared for you a minimal example of solving the problem by using **APP_INITIALIZER**. You will find him on [***StackBlitz](https://stackblitz.com/edit/angular-configuration-with-app-initializer)***

### The feedback is important and best way in medium.com is clicking multiple times on clap icon 👏 on your left . If you click on it, I will know that my articiles has value for you ❤️ and I will be encouraged to write more 📙. Thanks!
>  [Follow me](https://twitter.com/marcin_milewicz) on Twitter if you want to be updated about new great Angular and frontend stuff! *😄*