How do you manage environment-specific configuration in Angular?
1. What is environment-specific configuration?
Environment-specific configuration means keeping configuration values different depending on where the Angular application is running.
For example:
| Environment | API URL |
|---|---|
| Development | https://localhost:7001/api |
| UAT | https://uat-api.jntech.in/api |
| Production | https://api.jntech.in/api |
Instead of hard-coding the API URL inside Angular services, we keep these values in environment files and let the Angular build configuration select the appropriate file.
A common structure is:
src/
└── environments/
├── environment.ts
├── environment.uat.ts
└── environment.production.ts
2. Full Simple Sample Program
Suppose Angular communicates with an ASP.NET Core Web API.
Project structure
src/
│
├── app/
│ ├── models/
│ │ └── product.ts
│ │
│ ├── services/
│ │ └── product.ts
│ │
│ ├── app.ts
│ ├── app.html
│ └── app.config.ts
│
├── environments/
│ ├── environment.ts
│ ├── environment.uat.ts
│ └── environment.production.ts
│
└── main.ts
environment.ts — Development
export const environment = {
production: false,
apiUrl: 'https://localhost:7001/api'
};
environment.uat.ts — UAT
export const environment = {
production: false,
apiUrl: 'https://uat-api.jntech.in/api'
};
environment.production.ts — Production
export const environment = {
production: true,
apiUrl: 'https://api.jntech.in/api'
};
product.ts
export interface Product {
id: number;
name: string;
price: number;
}
services/product.ts
import { inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Product } from '../models/product';
import { environment } from '../../environments/environment';
@Injectable({
providedIn: 'root'
})
export class ProductService {
private http = inject(HttpClient);
private apiUrl = `${environment.apiUrl}/products`;
getProducts(): Observable<Product[]> {
return this.http.get<Product[]>(this.apiUrl);
}
}
Notice something important:
import { environment } from '../../environments/environment';
We always import environment, not:
environment.production
environment.uat
Angular's build configuration performs the replacement.
app.ts
import { Component, inject, OnInit } from '@angular/core';
import { ProductService } from './services/product';
import { Product } from './models/product';
@Component({
selector: 'app-root',
standalone: true,
templateUrl: './app.html'
})
export class App implements OnInit {
private productService = inject(ProductService);
products: Product[] = [];
ngOnInit(): void {
this.productService
.getProducts()
.subscribe({
next: data => {
this.products = data;
},
error: error => {
console.error(error);
}
});
}
}
app.html
<h1>Products</h1>
@for (product of products; track product.id) {
<div>
{{ product.name }} - {{ product.price }}
</div>
}
app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient()
]
};
main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { App } from './app/app';
import { appConfig } from './app/app.config';
bootstrapApplication(App, appConfig)
.catch(err => console.error(err));
3. Configure angular.json
The important part is telling Angular which environment file should be used for each configuration.
A simplified configuration could look like this:
{
"projects": {
"my-app": {
"architect": {
"build": {
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.production.ts"
}
]
},
"uat": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.uat.ts"
}
]
},
"development": {
}
}
}
}
}
}
}
The key feature is:
"fileReplacements"
It tells the Angular build system:
When building this configuration, replace one file with another.
4. Running Different Environments
Development
ng serve
or explicitly:
ng serve --configuration development
Uses:
environment.ts
Therefore:
https://localhost:7001/api
UAT
ng serve --configuration uat
or build it:
ng build --configuration uat
Angular replaces:
environment.ts
with:
environment.uat.ts
Therefore:
https://uat-api.jntech.in/api
Production
ng build --configuration production
Angular replaces:
environment.ts
with:
environment.production.ts
Therefore:
https://api.jntech.in/api
5. How does it work?
The Angular service contains:
import { environment } from '../../environments/environment';
and:
private apiUrl = `${environment.apiUrl}/products`;
During development:
ProductService
↓
environment.ts
↓
https://localhost:7001/api
During UAT build:
ProductService
↓
environment.ts
↓
Angular file replacement
↓
environment.uat.ts
↓
https://uat-api.jntech.in/api
During production build:
ProductService
↓
environment.ts
↓
Angular file replacement
↓
environment.production.ts
↓
https://api.jntech.in/api
So ProductService doesn't need to know which environment is running.
6. Generating Angular Environment Configuration
Angular CLI provides:
ng generate environments
Short form:
ng g environments
This can create the initial environment setup and add the corresponding file replacement configuration.
You can then extend it for environments such as:
Development
SIT
UAT
Production
For example:
environment.ts
environment.sit.ts
environment.uat.ts
environment.production.ts
7. What should be stored in environment configuration?
Typical values include:
export const environment = {
production: false,
apiUrl: 'https://localhost:7001/api',
authApiUrl: 'https://localhost:7002/api',
loggingEnabled: true,
applicationName: 'JNTech'
};
Then:
environment.apiUrl
or:
environment.loggingEnabled
8. Important: Don't Store Secrets Here
Angular environment files are not secure secret storage.
Do not put values such as:
export const environment = {
databasePassword: 'mypassword',
jwtSecret: 'secret-key',
sqlConnectionString: '...',
privateApiKey: '...'
};
Why?
Because Angular runs in the browser.
The compiled JavaScript is downloaded to the user's computer, so values included in the Angular bundle can potentially be inspected.
Therefore:
Angular Environment
↓
Public/non-secret configuration
ASP.NET Core / Server
↓
Secrets
↓
Environment variables / Key Vault / secret store
For example, the Angular application can know:
apiUrl: 'https://api.jntech.in'
But the SQL Server connection string should stay in ASP.NET Core/server-side configuration.
9. Build-Time Configuration vs Runtime Configuration
This is an important advanced distinction.
The standard Angular environment-file approach is primarily build-time configuration.
Suppose you run:
ng build --configuration production
The resulting bundle contains the production values.
If you later want to deploy the same build artifact to UAT and Production with different API URLs, environment file replacement alone is not ideal.
You would normally need:
UAT
↓
ng build --configuration uat
↓
UAT build
Production
↓
ng build --configuration production
↓
Production build
For CI/CD scenarios where you want:
Build once
↓
Deploy same artifact
├── SIT
├── UAT
└── Production
you can use runtime configuration, such as loading a JSON configuration file when the application starts.
For example:
assets/config.json
That is a different pattern from Angular's normal environment-file replacement.
10. Key Points
- Environment configuration stores values that differ between Development, SIT, UAT, and Production.
- Angular commonly uses environment files such as:
environment.ts
environment.uat.ts
environment.production.ts
- Environment configurations can use Angular build file replacements.
- Application code continues importing:
import { environment } from '../environments/environment';
- Build with:
ng build --configuration production
- UAT can use:
ng build --configuration uat
- API base URLs are a common environment-specific setting.
- Angular environment values are included in client-side code, so do not store secrets in them.
- Environment files are primarily a build-time configuration technique.
- Runtime configuration is preferable when the same Angular build must be deployed to multiple environments with different settings.
Interview Questions and Answers
1. How do you manage environment-specific configuration in Angular?
Angular can use separate environment files and build configurations for Development, UAT, and Production. Angular's fileReplacements configuration selects the appropriate environment values during the build.
2. What is an Angular environment file?
It is a TypeScript file containing environment-dependent configuration values such as API URLs and feature settings.
Example:
export const environment = {
production: false,
apiUrl: 'https://localhost:7001/api'
};
3. How do you create Angular environment files?
You can generate the initial environment configuration using:
ng generate environments
Then additional files can be added for environments such as SIT or UAT.
4. How does Angular choose the production environment?
Using the build configuration:
ng build --configuration production
The configured fileReplacements can replace:
environment.ts
with:
environment.production.ts
5. How do you access environment variables inside a service?
Import the environment:
import { environment } from '../../environments/environment';
Then:
private apiUrl = environment.apiUrl;
6. Can we store passwords or secrets in Angular environment files?
No. Angular code executes in the browser and its compiled files can be inspected. Secrets such as database passwords, private API keys, and signing keys should remain on the server.
7. Where should the ASP.NET Core API URL be stored?
A non-secret API base URL can be stored in Angular environment configuration:
apiUrl: 'https://api.jntech.in/api'
8. What is fileReplacements in Angular?
It tells the Angular build system to replace one source file with another for a particular build configuration.
Example:
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.production.ts"
}
]
9. Are Angular environment files runtime configuration?
Normally, no. They are primarily build-time configuration because the selected values become part of the generated JavaScript bundle.
10. What is the difference between build-time and runtime Angular configuration?
Build-time configuration:
environment.ts
↓
ng build
↓
JavaScript bundle contains configuration
Runtime configuration:
Angular application starts
↓
Loads config.json / configuration endpoint
↓
Gets environment settings
Runtime configuration is especially useful when you want to build Angular once and deploy the same artifact to SIT, UAT, and Production with different API URLs.