Angular How-to: Editable Config Files

In this post, Premier Developer consultant Laurie Atkinson walks through how to allow editing of your Angular configuration files after your app has been built, bundled, and deployed.

The Angular-CLI is the recommended way to build a production-ready app, complete with bundling, uglifying, and tree-shaking. An Angular-CLI generated application even comes with a mechanism for creating environment-specific versions. However, those configuration files are in TypeScript and do not allow editing by IT staff or automated deployment tools such as VSTS. This post provides the steps and code samples for using a JSON configuration file, which can be customized for multiple environments.

Define TypeScript interface for config settings

The use of interfaces in an Angular app provides intellisense and type-safety for your entities. For this example, refer to this sample configuration file.


export interface IAppConfig {
    env: {
        name: string;
    appInsights: {
        instrumentationKey: string;

    logging: {
        console: boolean;
        appInsights: boolean;
    aad: {
        requireAuth: boolean;
        tenant: string;
        clientId: string;

    apiServer: {
        metadata: string;
        rules: string;

Create JSON config files

A convenient place to store configuration files is under the assets folder of your project. Using the interface defined above, sample files could look as follows:


    "env": {
    "name": "DEV"
    "appInsights": {
    "instrumentationKey": "<dev-guid-here>"
    "logging": {
    "console": true,
    "appInsights": false
    "aad": {
    "requireAuth": true,
    "tenant": "<dev-guid-here>",
    "clientId": "<dev-guid-here>"
    "apiServer": {
    "metadata": "",
    "rules": ""

assets\config\config.deploy.json (Note placeholders that are replaced during deployment)

    "env": {
    "name": "#{envName}"
    "appInsights": {
    "instrumentationKey": "#{appInsightsKey}"
    "logging": {
    "console": true,
    "appInsights": true
    "aad": {
    "requireAuth": true,
    "tenant": "#{aadTenant}",
    "clientId": "#{aadClientId}"
    "apiServer": {
    "metadata": "https://#{apiServerPrefix}",
    "rule": "https://#{apiServerPrefix}",

Continue to use environment.ts with Angular-CLI build

The Angular-CLI creates several TypeScript environment files in the environments folder. They will still be used, but contain only the environment name.


export const environment = {
    name: 'dev'


export const environment = {
    name: 'deploy'


"environmentSource": "environments/environment.ts",
"environments": {
    "dev": "environments/environment.ts",
    "deploy": "environments/environment.deploy.ts"

Create a service to read config file

This service will read the correct config file and store the result in a static field in this class..

app.config.ts (Note the use of the interface defined above and config file naming convention to retrieve the appropriate file.)

import { Injectable } from '@angular/core’;
import { Http, Response } from '@angular/http';
import { environment } from '../environments/environment';
import { IAppConfig } from './models/app-config.model';

export class AppConfig {

    static settings: IAppConfig;

constructor(private http: Http) {}

    load() {
        const jsonFile = `assets/config/config.${}.json`;
        return new Promise<void>((resolve, reject) => {
            this.http.get(jsonFile).toPromise().then((response : Response) => {
               AppConfig.settings = <IAppConfig>response.json();
            }).catch((response: any) => {
               reject(`Could not load file '${jsonFile}': ${JSON.stringify(response)}`);

Load config file prior to app creation

Angular includes a token named APP_INITIALIZER that allows our app to execute code when the application is initialized. In the app module, use this token to invoke the load method in our config service. Since our method returns a promise, Angular will delay the initialization until the promise is resolved.


import { APP_INITIALIZER } from '@angular/core';
import { AppConfig } from './app.config';

export function initializeApp(appConfig: AppConfig) {
  return () => appConfig.load();

    imports: [ , , , ],
    declarations: [ . . . ],
providers: [
       { provide: APP_INITIALIZER,
         useFactory: initializeApp,
         deps: [AppConfig], multi: true }
    bootstrap: [
export class AppModule { }

Consume the app settings throughout the application

The config settings are now available from anywhere in the application and they include type-checking provided by the interface.

export class DataService {
    protected apiServer = AppConfig.settings.apiServer;
    . . .
    if (AppConfig.settings.aad.requireAuth) { . . . }
export class LoggingService {
    . . .
    instrumentationKey: AppConfig.settings && AppConfig.settings.appInsights ?
                        AppConfig.settings.appInsights.instrumentationKey : ''
    . . .
    if (AppConfig.settings && AppConfig.settings.logging) { . . . }

Note: to build a production version of the app using an environment name other than prod, use this command:

ng build --target=production --environment=deploy

Comments (13)

  1. MrO2You says:

    Great post! This exactly addresses a challenge our dev team has been trying to work through. Thanks for putting this together.

    1. Laurie Atkinson says:

      Wonderful to hear that the post helped your team. That’s the goal of this blog. Thanks for the feedback.

  2. Kw says:

    Hi there, any idea to protect the config file from direct access?
    E.G : Prevent access from using path like {domain}\assets\config\config.deploy.json

    1. Laurie Atkinson says:

      I did some research and asked a teammate that specializes in security and identity (thanks, Marius) and unfortunately the answer is ‘no’. Preventing unauthorized access to static files delivered and used in the browser is not possible and that’s why OAuth2 spec calls a browser app a public (as opposed to confidential) client. You could encrypt the file, but the decryption keys must be in the browser. The only way to mitigate is to expose a service that consumes the file on the server and the browser calls the service.

  3. Shobhitvaish says:

    Great article!
    One question though – Could you please help me in understanding how placeholders would be replaced during deployment? I am using continuous integration with VSTS and my angular SPA is deployed in Azure web app.

    1. Laurie Atkinson says:

      There is a Replace Tokens build task that you can add to your VSTS build process.

  4. Andrea Re says:

    Great post! This exactly addresses a challenge I’m working on!! Thanks.

  5. Felip says:

    Congratulations for the article, it’s really helpful. However, I’m trying to follow the steps on an Angular 6 application and there are no “environmentSource’ and ‘environments’ keys in the .angular-cli.json file (now named angular.json). Could you please update the tutorial to support Angular 6?

    Thanks a lot,

    1. Laurie Atkinson says:

      For Angular 6, you can specify the environment in the new angular.json file:
      “build”: {
      . . .
      “configurations”: {
      “deploy”: {
      “fileReplacements”: [
      “src”: “src/environments/environment.ts”,
      “replaceWith”: “src/environments/environment.deploy.ts”

  6. Thibaud Lacan says:

    Thank you for this post, this is exactly what i was looking for!
    Unfortunately i’m getting the following error in my browser console when ng serve:
    Could not load file ‘assets/config/’: {}

    I am using angular 5.2 and followed all the steps.
    Also, in my project i have the and config.deploy.json correctly placed under assets/config/
    Anyone faced the same issue?

  7. Lasse says:

    Hi Laurie

    Thanks for a great article.

    I was wondering if you have any tips on dynamically replacing the configuration file for each deployment when using a dockerized Angular app (e.g. a container with nginx hosting an Angular app)?

    I think a possible solution is to volume mount a configuration file on the host, which is mapped to the corresponding config json file in the apps ‘assets/config/’ folder. Do you see any issues or possible improvements with this approach?

  8. Thibaud Lacan says:

    Great article thanks!
    Be careful not to use HttpClient instead of Http in AppConfig, I was trying to use HttpClient instead and it doesn’t work the same way (probably some lifecycle difference), took me a day to figure it out!

  9. SandyVeliz says:

    Hi! may i ask, my AppSettings.deploy.json dosnt get filled by the aplication settings of the Appservice in Azure, local works great but i cant get the settings from Azure

Skip to main content