Angular CLI and OS Environment Variables
Sara Lara

Amazing job Sara, you save me a lot of time, thank you!!

I have tried an slightly different version of your feature that works well with our use case. At work, we have different environments (local, development, pre-production, production, test ,…) for each project, not always all and not always with that names, and we were used to store the URL that points to the REST API in different environment.*.ts files with Angular CLI, like this:

export const environment = {
production: true,

We ended up with several files environment.*.ts files (one for each environment) and if you messed up with the addresses the deployed application will not work as expected, causing real panic if the time is a problem.

We also had to add new environments to .angular-cli.json file:

"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"pre": "environments/environment.pre.ts",
"pro": "environments/",
"test": "environments/environment.test.ts"

And create a new script to build sources for each environment at package.json:

"scripts": {
"ng": "ng",
"start": "ng serve --port 8000",
"build": "ng build",
"build-pre": "ng build --target=production --environment=pre",
"build-pro": "ng build --target=production --environment=pro",
"build-test": "ng build --target=production --environment=test",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"

Each time we have to deploy a new web application we have to ask the DevOps team for the addresses of each environment they have created for this app, then create needed environment.*.ts files with that addresses, add new environments to .angular-cli.json, add the build script in package.json and commit this files to the repository. This could lead to a problem if you need to commit sensitive information.

DevOps team wait for our commit and deploy the web application into the new environment cloning the repository, building source files with each specific script and deploying it into a Web Server, with Jenkins tasks.

Talking with my colleague Manuel, of the DevOps team, told me: “buddy, it has to be a better way to do this, what if I can export an OS environment variable and you modify your code to read this variable and never ever change that files I always have to ask you?”

That is how I discovered your article, and claim the sky for it: “Great, somebody else had the same problem as me and had already solved it!”
Your solution worked perfectly at first time, but I realized that in the way you solved it, I still have to create different environment files, and my colleagues of the DevOps team will have to create a .env file for each deploy. For our use case, it would be better to use regular old environment variables.

First I removed all environment.*.ts files except environment.ts source file and I modified .angular-cli.json file, creating an environment called ‘env’ that will use the same environment file for all environments:

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

I extracted your set-env.ts file to the root level as long as it is not a source file and it was being compiled in production builds, and I modify it like this:

import { writeFile } from 'fs';

const targetPath = `./src/environments/environment.ts`;
const envConfigFile = `
export const environment = {
production: "${process.env.PRODUCTION}",
API_BASE_URL: "${process.env.API_BASE_URL}"

writeFile(targetPath, envConfigFile, function (err) {
if (err) {

console.log(`Output generated at ${targetPath}`);

To battle with OS environment variables and avoid developers having to export tons of variables I tried cross-env, and perfectly fit in the use case.
cross-env allows you to export an environment variable in a npm script across platforms. Here is the scripts section of the modified package.json

"scripts": {
"ng": "ng",
"config": "ts-node set-env.ts",
"start": "cross-env PRODUCTION=false API_BASE_URL=http://localhost:8080 npm run config && ng serve",
"build": "npm run config && ng build --environment=env",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"

As you can see, start script is not so beautiful, specially if we need to export many environment variables, but it works and we only need a build task for any new environment.

In that way, DevOps team does not need our help to create a new environment for an application anymore. The deployment task for each environment in Jenkins starts like this:

# Export of needed environment variables
export PRODUCTION=true
export API_BASE_URL=
# API_BASE_URL will be different in each environment
# Install dependencies
npm install
# Build sources
npm run build
# Backup and deploy into a Web Server


This is the case of an automated deployment process you stated in your article, and I just want to show you how we have included your solution in our workflow.

In one hand, since there is now only one build task for any environment, there is no need to modify the code to create a new one, delegating this task on the DevOps team.

In the other hand, you should not use this approach if you need to export sensitive information and the repository is public, because you would be exposing this info in package.json npm scripts..

To solve this problem you can ask developers to export that sensitive values in their OS environment variables or use a mixed approach, combining the read of non sensitive environment variables and ignored file sensitive variables.

I forked your repo and modify it to work with this approach here, in case you want to check it out, thanks for your time!