This episode covers configuration and environment: environment files and build configurations, setting up the Angular CLI and build targets, managing feature flags and API endpoints, and secure secrets management and production settings.

The same application runs in different environments: development, staging, and production. API URLs, feature flags, and other settings must change per environment without changing code.
Episode 11 covers environment files and build configurations, setting up the Angular CLI and build targets, managing feature flags and API endpoints, and secure practices for secrets and production settings. Good configuration makes moving between environments seamless.
Since Angular 15, a project has two environment files in src/environments:
src/environments/environment.ts
src/environments/environment.development.tsenvironment.ts is used for production, while environment.development.ts is for development. Fill the files with environment-specific values:
export const environment = {
production: true,
apiUrl: 'https://api.toko-online.example.com',
namaAplikasi: 'Toko Online',
};Environment files should only contain values that are safe for the public, such as API URLs and the application name. Sensitive values must never live here, because these files end up inside the bundle.
Each environment is mapped via fileReplacements in angular.json. A production build swaps the environment file for the production version.
{
"production": {
"budgets": [],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.development.ts"
}
]
}
}When ng build --configuration=production runs, Angular swaps the environment file according to the mapping. You can also add custom configurations, such as staging, with ng build --configuration=staging.
ng build --configuration=production
ng build --configuration=staging --output-path=dist/staging--output-path moves the build output to a different folder so staging and production don't overwrite each other. For development, ng serve uses the development configuration automatically.
Each configuration can set targets such as output-hashing, source-map, optimization, and budgets. Here's a production example that enables optimization:
{
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"buildOptimizer": true
}outputHashing: 'all' names files with content hashes so browsers cache them correctly and don't serve stale versions after a deploy.
Feature flags control which features are active in a given environment. A simple example based on the environment:
export const environment = {
production: true,
fitur: {
checkout: true,
promo: true,
notifikasi: false,
},
};Use the flag in a component: if (environment.fitur.checkout). For control without a redeploy, pull runtime configuration from a server — a pattern called runtime config.
Instead of hardcoding in the environment, the application loads configuration from an endpoint at startup:
export interface RuntimeConfig {
apiUrl: string;
fitur: Record<string, boolean>;
}
export async function muatConfig(): Promise<RuntimeConfig> {
const res = await fetch('/assets/config.json');
if (!res.ok) {
throw new Error('Gagal memuat konfigurasi runtime');
}
return res.json();
}muatConfig fetches config.json from the assets folder. An admin can change the API endpoint or turn features on without rebuilding the application — very useful for controlling flags in production.
Frontend code can be read by anyone. API keys, tokens, and credentials must never be stored in environment files or NEXT_PUBLIC_*-style variables, because they all end up in the bundle. Secrets must be used in the backend or injected via server-side rendering.
For development, the CLI provides a proxy so API requests don't hit CORS:
{
"/api": {
"target": "http://localhost:8080",
"secure": false,
"changeOrigin": true
}
}Run it with ng serve --proxy-config=proxy.conf.json. Requests to /api/... are forwarded to localhost:8080 — without leaking internal URLs to the production frontend.
For production: enable optimization and hashing, disable source maps, set bundle budgets, and audit dependencies with npm audit. Pipeline secrets (such as deploy tokens) are managed in the CI/CD system — not inside the repository.
Key takeaways:
fileReplacements swaps them at build time.angular.json control targets like optimization and hashing.In the next episode, episode 12, we'll cover security and auth — JWT authentication patterns, protecting routes with auth guards, secure token storage and HTTP calls, and role-based authorization and permission checks.