Using Environment Variables in Angular: A Comprehensive Guide to Managing Configurations
Environment variables in Angular are a powerful way to manage configuration settings that vary across different environments, such as development, testing, and production. By using environment variables, developers can maintain a single codebase while adapting the application’s behavior—such as API endpoints, feature flags, or debugging options—based on the deployment context. This blog provides an in-depth guide to using environment variables in Angular, covering their setup, usage, best practices, and advanced techniques. Whether you’re a beginner or an experienced developer, this tutorial will help you leverage environment variables to build flexible, maintainable Angular applications.
What Are Environment Variables in Angular?
Environment variables are configuration values that an application uses to adapt its behavior depending on the environment it’s running in. In Angular, environment variables are typically stored in configuration files within the src/environments/ directory. These files define settings like API URLs, authentication keys, or logging levels, which differ between environments (e.g., local development vs. production).
The Angular Command Line Interface (CLI) provides built-in support for environment variables, making it easy to switch configurations during development, testing, or deployment. By separating environment-specific settings from the codebase, you ensure that sensitive data (like API keys) isn’t hardcoded and that the application remains portable across environments.
Why Use Environment Variables?
Using environment variables offers several benefits:
- Separation of Concerns: Keeps configuration separate from application logic, improving maintainability.
- Security: Prevents sensitive data, such as API keys, from being exposed in source code or version control.
- Flexibility: Allows the same codebase to run in different environments with minimal changes.
- Consistency: Ensures predictable behavior across development, staging, and production environments.
- Ease of Use: The Angular CLI automates environment switching during builds, reducing manual configuration.
To understand how Angular projects are structured, including the environments/ directory, see Angular Create a New Project.
Setting Up Environment Variables in Angular
The Angular CLI generates a default environment setup when you create a new project. Let’s walk through the process of setting up and using environment variables, starting with a new project.
Step 1: Create a New Angular Project
If you don’t already have a project, create one using the Angular CLI:
ng new my-app
- Choose Yes for routing and CSS (or your preferred stylesheet format) when prompted.
- Navigate to the project directory:
cd my-app
For a detailed guide on project creation, refer to Angular Create a New Project.
Step 2: Explore the Default Environment Files
The CLI generates an src/environments/ directory with two files:
- environment.ts: Used for the development environment.
- environment.prod.ts: Used for the production environment.
Open environment.ts:
export const environment = {
production: false
};
- This file defines settings for development. The production: false flag indicates a non-production environment, often used to enable debugging or logging.
Open environment.prod.ts:
export const environment = {
production: true
};
- This file is used when building for production (e.g., ng build --prod). The production: true flag enables optimizations like minification and Ahead-of-Time (AOT) compilation.
These files are minimal by default, but you can add custom variables, such as API endpoints or feature toggles, as needed.
Step 3: Add Custom Environment Variables
Let’s add configuration settings to both files. For example, suppose your app needs an API URL and a feature flag for enabling analytics.
Update environment.ts:
export const environment = {
production: false,
apiUrl: 'http://localhost:3000/api',
enableAnalytics: true
};
Update environment.prod.ts:
export const environment = {
production: true,
apiUrl: 'https://api.myapp.com',
enableAnalytics: false
};
- Explanation:
- apiUrl: Specifies the backend API endpoint, differing between local development and production.
- enableAnalytics: A boolean flag to toggle analytics, enabled locally but disabled in production (e.g., for cost savings or privacy).
Step 4: Configure Angular to Use Environment Files
The Angular CLI automatically uses the appropriate environment file based on the build configuration. The angular.json file defines these configurations under the configurations section.
Open angular.json and locate the build section:
"build": {
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true
}
}
}
- Key Point: The fileReplacements array tells the CLI to replace environment.ts with environment.prod.ts during a production build (ng build --prod or ng build --configuration=production).
For development builds (ng build or ng serve), the CLI uses environment.ts by default.
Step 5: Access Environment Variables in Your Code
To use environment variables, import the environment object into your components, services, or other files.
Create a service to fetch data using the API URL. Run:
ng generate service api
Update src/app/api.service.ts:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../environments/environment';
@Injectable({
providedIn: 'root'
})
export class ApiService {
constructor(private http: HttpClient) {}
getData() {
return this.http.get(`${environment.apiUrl}/data`);
}
}
- Explanation:
- Import environment from ../environments/environment.
- Use environment.apiUrl to construct the API endpoint.
- The CLI ensures the correct environment file (development or production) is used based on the build.
To use this service in a component, update app.component.ts:
import { Component, OnInit } from '@angular/core';
import { ApiService } from './api.service';
import { environment } from '../environments/environment';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
data: any;
analyticsEnabled = environment.enableAnalytics;
constructor(private apiService: ApiService) {}
ngOnInit() {
if (this.analyticsEnabled) {
console.log('Analytics is enabled');
}
this.apiService.getData().subscribe((response) => {
this.data = response;
});
}
}
- Explanation:
- environment.enableAnalytics controls whether analytics-related logic runs.
- The ApiService uses the environment’s apiUrl for HTTP requests.
- Learn about services in [Angular Services](/angular/services/angular-services) and HTTP requests in [Fetch Data with HttpClient](/angular/services/fetch-data-with-httpclient).
Update app.component.html to display the data:
My App
Analytics Enabled: { { analyticsEnabled }}
{ { data | json }}
- The json pipe formats the data for display. Learn about pipes in [Angular Pipes](/angular/pipes/angular-pipes).
Step 6: Test Environment Switching
To test the development environment:
ng serve
- Visit http://localhost:4200. The app uses http://localhost:3000/api and shows analyticsEnabled: true.
To test the production environment:
ng build --configuration=production
- The CLI replaces environment.ts with environment.prod.ts, using https://api.myapp.com and analyticsEnabled: false.
- Serve the production build locally using a tool like http-server:
npm install -g http-server http-server dist/my-app
- Learn about production builds in [Angular Deploy Application](/angular/advanced/angular-deploy-application).
Adding Custom Environments
By default, Angular supports development and production environments, but you can add custom environments, such as staging or testing.
Step 1: Create a New Environment File
Create src/environments/environment.staging.ts:
export const environment = {
production: false,
apiUrl: 'https://staging.api.myapp.com',
enableAnalytics: true
};
Step 2: Update angular.json
Add a new configuration in angular.json under build.configurations:
"build": {
"configurations": {
"production": { ... },
"staging": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.staging.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false
}
}
}
Also, add the configuration to serve.configurations:
"serve": {
"configurations": {
"production": { "browserTarget": "my-app:build:production" },
"staging": { "browserTarget": "my-app:build:staging" }
}
}
Step 3: Build or Serve with the Custom Environment
Serve the staging environment:
ng serve --configuration=staging
Build for staging:
ng build --configuration=staging
- The app now uses environment.staging.ts, with apiUrl: 'https://staging.api.myapp.com'.
Best Practices for Using Environment Variables
To maximize the benefits of environment variables, follow these practices:
- Avoid Hardcoding Sensitive Data: Store API keys or secrets in environment variables, not in source code. For production, consider injecting secrets via server-side environment variables or a secrets manager.
- Use Descriptive Keys: Name variables clearly (e.g., apiUrl instead of url) to avoid confusion.
- Keep Environment Files Simple: Only include settings that change across environments. Static configurations can live in regular TypeScript files.
- Version Control Safely: Add environment.prod.ts and other sensitive files to .gitignore if they contain secrets. Instead, provide a template (e.g., environment.prod.template.ts) for team members to copy and customize.
- Type Safety: Define an interface for environment variables to ensure consistency:
export interface Environment { production: boolean; apiUrl: string; enableAnalytics: boolean; } export const environment: Environment = { ... };
- Test Configurations: Verify environment switching during development and before deployment to catch misconfigurations.
Advanced Use Cases
Dynamic Environment Variables at Runtime
Angular’s environment files are replaced at build time, meaning the configuration is baked into the bundle. For runtime configuration (e.g., loading settings from a server), you can fetch a configuration file:
- Create a JSON file in src/assets/config.json:
{
"apiUrl": "https://dynamic.api.myapp.com",
"enableAnalytics": true
}
- Create a service to load the configuration:
ng generate service config
- Update config.service.ts:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
interface Config {
apiUrl: string;
enableAnalytics: boolean;
}
@Injectable({
providedIn: 'root'
})
export class ConfigService {
private config: Config | null = null;
constructor(private http: HttpClient) {}
loadConfig(): Observable {
return this.http.get('/assets/config.json');
}
setConfig(config: Config) {
this.config = config;
}
getConfig(): Config {
if (!this.config) {
throw new Error('Config not loaded');
}
return this.config;
}
}
- Load the configuration during app initialization in app.module.ts:
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { ConfigService } from './config.service';
export function initializeApp(configService: ConfigService) {
return () => configService.loadConfig().toPromise().then(config => configService.setConfig(config));
}
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, AppRoutingModule, HttpClientModule],
providers: [
{
provide: APP_INITIALIZER,
useFactory: initializeApp,
deps: [ConfigService],
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule {}
- This ensures the app loads config.json before bootstrapping. Learn about HTTP requests in [Fetch Data with HttpClient](/angular/services/fetch-data-with-httpclient).
Environment Variables in CI/CD Pipelines
In continuous integration/continuous deployment (CI/CD) pipelines, you can inject environment variables during the build process:
- Store secrets in your CI/CD system (e.g., GitHub Actions, Jenkins).
- Create a script to generate environment.prod.ts during the build:
echo "export const environment = { production: true, apiUrl: '$API_URL', enableAnalytics: $ENABLE_ANALYTICS };" > src/environments/environment.prod.ts
- Run the production build:
ng build --configuration=production
This approach keeps sensitive data out of version control.
Troubleshooting Common Issues
- Environment Not Switching:
- Verify fileReplacements in angular.json for the correct configuration.
- Ensure you’re using the right build command (e.g., ng build --configuration=production).
- Variables Undefined:
- Check the import path: import { environment } from '../environments/environment'.
- Confirm the variable exists in the environment file.
- Sensitive Data Exposed:
- Add environment.prod.ts to .gitignore and use a template file.
- Use runtime configuration for secrets instead of build-time variables.
- Build Errors:
- Ensure all environment files have the same structure (same keys, different values).
- Update the CLI if issues persist:
npm install -g @angular/cli
FAQs
What are environment variables in Angular?
Environment variables are configuration settings stored in files like environment.ts and environment.prod.ts, used to adapt an app’s behavior across different environments (e.g., development, production).
How do I add a custom environment like staging?
Create a new file (e.g., environment.staging.ts) and add a staging configuration in angular.json with fileReplacements to swap it during builds.
Can I change environment variables at runtime?
Angular’s environment files are build-time configurations. For runtime changes, load a configuration file (e.g., config.json) using HTTP or use server-side environment variables in CI/CD.
How do I secure sensitive data in environment files?
Avoid committing sensitive data to version control. Use .gitignore for environment.prod.ts, provide a template, or load secrets at runtime via a server or CI/CD pipeline.
Why is my production build not using environment.prod.ts?
Check angular.json for the production configuration’s fileReplacements section. Ensure you’re running ng build --configuration=production.
Conclusion
Environment variables are a cornerstone of building flexible, secure, and maintainable Angular applications. By leveraging Angular’s built-in environment system, you can manage configurations for different environments without duplicating code or exposing sensitive data. This guide has walked you through setting up environment files, accessing variables, creating custom environments, and handling advanced use cases like runtime configuration. With these skills, you’re equipped to build Angular apps that adapt seamlessly to any deployment context, from local development to production servers.
Start using environment variables in your Angular projects today, and take control of your app’s configuration with confidence!