Environment-specific Configuration
Environment Specific Configuration handles the challenge of loading different settings depending on whether your app is running locally, in a staging environment, or in production.
Overview
A common pattern in Node.js development is to have multiple .env files (e.g., .env.development, .env.staging, .env.production).
NestJS’s ConfigModule makes it easy to dynamically load the correct file based on the current NODE_ENV system variable.
Key Concepts
NODE_ENV: The standard Node.js environment variable. It usually dictates which configuration file to load.envFilePathArray: TheConfigModulecan accept an array of file paths. It will attempt to load them in order, with the first file taking precedence.- Fallback Configurations: You can provide a base
.envfile and override specific values with a.env.productionfile.
Code Examples
1. Dynamic File Loading
This is the standard pattern for dynamically loading the correct .env file based on the environment.
// app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [
ConfigModule.forRoot({
// If NODE_ENV is 'production', it loads '.env.production'.
// If NODE_ENV is undefined, it defaults to '.env.development'.
envFilePath: `.env.${process.env.NODE_ENV || 'development'}`,
isGlobal: true,
}),
],
})
export class AppModule {}
2. Cascading / Override Configurations
Sometimes you want a base configuration file, but you want to override a few specific keys for local development.
// .env (Base)
DATABASE_USER=admin
DATABASE_PASS=secret
FEATURE_FLAG_NEW_UI=false
// .env.local (Overrides)
FEATURE_FLAG_NEW_UI=true
You can pass an array to envFilePath. NestJS uses the first value it finds.
// app.module.ts
ConfigModule.forRoot({
// NestJS checks '.env.local' FIRST.
// If the key isn't there, it falls back to '.env'.
envFilePath: ['.env.local', '.env'],
})
3. Ignoring Files in Production
In modern cloud deployments (like AWS ECS, Kubernetes, Heroku), you usually do not deploy .env.production files. Instead, you set the environment variables directly in the cloud provider’s dashboard or orchestration scripts.
To prevent NestJS from looking for a file that doesn’t exist, use ignoreEnvFile.
ConfigModule.forRoot({
// Don't even bother looking for a .env file if we are in production
ignoreEnvFile: process.env.NODE_ENV === 'production',
})
Best Practices
- Do not commit environment-specific files: While it’s okay to commit a
.env.examplefile, you should generally add*.env*to your.gitignoreto prevent accidentally committing.env.productionfiles containing real production passwords. - Use
NODE_ENVstrictly: Reserve the values ofNODE_ENVto standard strings likedevelopment,staging,production, andtest. Do not use it for feature flagging (e.g.,NODE_ENV=production_new_ui). - Use
.env.testfor Jest: When running unit or e2e tests, ensure you load a.env.testfile that connects to a separate testing database. You do not want your unit tests accidentally dropping tables in your development database!