Ever pondered how to call multiple APIs, colors, or headlines for the same application from several environments? Production APIs and test APIs are undoubtedly distinct and need to be utilized extremely carefully. When launching a project, we won't manually alter every API call and sentence structure. This is dangerous and should not be done. With Angular, it's simple to have distinct setups for various environments. Because of this, we can use and deploy to as many environments and stages as necessary without ever having to alter the code. Environment files is the name of it.


To put it briefly, we can have two environment files: environment.development.ts for the development stage and environment.ts for the production stage. The appropriate environment file will then be used, based on where we are distributing our program.

There are very few configurations needed, and there is a significant gain. I'll walk you through the process in this post and give an example of using various texts and APIs.

Getting started
Create a new app: ng new angular-environment-demo --standalone false.
Generate environment files: ng generate environments.

Note. As from the Angular 15.1 environment files are not generated automatically.

Environment file hierarchy
The identical item will initially be present in both the environments.ts and the environments.development.ts. Both objects should have the same key and all settings should be done with them.

For example, you have the following in that file if the environment.development.ts has a key-value pair like: "weather_status": "Good" and the environment.ts will not utilize it. The weather status is ''. This is due to the fact that you are using it in the code, and your code will utilize [this will be explained later] when it looks for it in the environment file. Compilation errors result from your code still searching for this even if it is pointing to another environment file.

Let's create two distinct page titles.

You can utilize the environment file's values in the app.component.ts file or any other ts file by accessing them as follows: environment.\<value you wish to access.>>. Here's an illustration of how to use the pageTitle in the app.component.ts ngOnInit.

Notice the import on line 2. For now, you can import any of the environment files. On line 13, we are assigning the value of ‘pageTitle’ from the environment to ‘this. title’. In the HTML file, we are using the ‘title’ as below.

When you serve the application using: ng serve, you will be given the following screen.

When we do only: “ng serve”, the values from the ‘environment.development.ts’ file are used. If you want to use the configurations from the environment.ts file, you should add the following in the angular.json file.

"fileReplacements": [
  {
    "replace": "src/environments/environment.development.ts",
    "with": "src/environments/environment.ts"
  }
],


These codes should be added under "projects" -> "architect" -> "build" -> "configurations" -> "production" in the angular.json file. Below is a full example of the angular.json file:

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "angular-environment-demo": {
      "projectType": "application",
      "schematics": {
        "@schematics/angular:component": {
          "standalone": false
        },
        "@schematics/angular:directive": {
          "standalone": false
        },
        "@schematics/angular:pipe": {
          "standalone": false
        }
      },
      "root": "",
      "sourceRoot": "src",
      "prefix": "app",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:application",
          "options": {
            "outputPath": "dist/angular-environment-demo",
            "index": "src/index.html",
            "browser": "src/main.ts",
            "polyfills": [
              "zone.js"
            ],
            "tsConfig": "tsconfig.app.json",
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.css"
            ],
            "scripts": []
          },
          "configurations": {
            "stagging": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.stagging.ts"
                }
              ]
            },
            "production": {
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "500kb",
                  "maximumError": "1mb"
                },
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "2kb",
                  "maximumError": "4kb"
                }
              ],
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.development.ts",
                  "with": "src/environments/environment.ts"
                }
              ],
              "outputHashing": "all"
            },
            "development": {
              "optimization": false,
              "extractLicenses": false,
              "sourceMap": true,
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.development.ts"
                }
              ]
            }
          },
          "defaultConfiguration": "production"
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "configurations": {
            "stagging": {
              "buildTarget": "angular-environment-demo:build:stagging"
            },
            "production": {
              "buildTarget": "angular-environment-demo:build:production"
            },
            "development": {
              "buildTarget": "angular-environment-demo:build:development"
            }
          },
          "defaultConfiguration": "development"
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "buildTarget": "angular-environment-demo:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "polyfills": [
              "zone.js",
              "zone.js/testing"
            ],
            "tsConfig": "tsconfig.spec.json",
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.css"
            ],
            "scripts": []
          }
        }
      }
    }
  }
}

This file is the most important one when we want to make the best use of an environment file. To use the configuration from the environment.ts file, we need to serve the application with the following command: “ng serve --configuration=production”.

Note that you did not make any changes in the code, you have added only a new configuration and served the app using the new command. For example, if you are serving in production, you can use this command to serve in that environment. No changes in the code are required. It is common to have multiple environments used mostly for testing. When you need to accommodate a new environment, there are some steps to follow.

create a new environment file in the environment folder. For example, we can add environment.staging.ts.
Once this is created, do not forget to add values present in other environment files.

In the angular.json file, we need to add a new configuration under configuration.

The last part is still in the angular.json file. Now we need to add the configuration to serve the application using the respective environment file. These changes are done under "projects" -> "architect" -> "serve" -> "configurations"

We use the following command to serve the application using the settings found in the environment.stagging.ts file: ng serve --configuration=stagging. The screen that loads after serving is as follows.


Using environment files to use different APIs. Another powerful application of environment files is how easily, almost seamlessly it can be used to call different APIs for different environments.

Below are the steps.
Add the corresponding key-value pair in the environment object in all the environment files in your project, like below.
export const environment = {
    pageTitle: "Dinosaur",
    apiUrl: "https://dinosaur-facts-api.shultzlab.com/dinosaurs"
};

In your component.ts file, wherever required, you can call the web service in any method that you want.
For this example, we will be using the fetch method in a promise.
getInfo(){
  const myPromise = new Promise((resolve, reject) => {
    fetch(environment.apiUrl)
    .then((response) => response.json())
    .then((data) => {
      resolve(data)
    })
    .catch((error) => reject(error))
  });

  myPromise
  .then((result: any) => {
    const element = document.getElementById('txtResult');
    if (element) {
      element.innerHTML = JSON.stringify(result.slice(0, 5));
    }
    console.log(result.slice(0, 5));
  })
  .catch((error) => console.log(error))
  .finally(() => console.log('promise done'));
}

Notice that in the call, we are not passing any api. Instead, we are using the variable from the environment file.
At this point, the function is done and can be called when a button is clicked.
When we serve the application using: ng serve and click on the button, we get the following.

When we serve the application using ng serve --configuration=production, below is the output:

  • Note that there has been NO code change. We have only served the application using different serving configurations.
  • The same applies when you are deploying to an environment. Whether you are deploying your Angular app using Azure or something else, you are asked at some point the command to run the Angular application. Providing the correct serving configuration will use the required environment file and will display the corresponding information or call the desired API. No changes in code are required.

Conclusion
Environment files are very important and powerful. Maximizing their use will prevent you from doing manual changes when deploying in different stages.