Table of Contents
- Introduction to Configuration in NestJS
- Why Use
@nestjs/config
? - Installing and Setting Up
@nestjs/config
- Using
.env
Files for Environment Variables - Accessing Config Values in Services
- Configuration Namespaces and Validation
- Loading Custom Config Files
- Using ConfigService with DI
- Config Best Practices: Security, Scoping, and Defaults
- Example: Environment-Based Database Config
- Summary and What’s Next
1. Introduction to Configuration in NestJS
Configuration is crucial for managing different environments (development, staging, production), API keys, secrets, database URLs, and feature flags. Hardcoding such values is dangerous and unscalable. That’s where @nestjs/config
shines—offering a standardized way to manage configuration in a secure and scalable way.
2. Why Use @nestjs/config
?
NestJS’s @nestjs/config
package:
- Reads environment variables from
.env
files - Injects configuration using NestJS’s DI system
- Supports multiple environments
- Enables strong validation
- Helps organize and centralize configuration logic
3. Installing and Setting Up @nestjs/config
Install the package:
bashCopyEditnpm install @nestjs/config
Import the module in your root module (AppModule
):
tsCopyEditimport { ConfigModule } from '@nestjs/config';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true, // makes ConfigService available everywhere
envFilePath: '.env', // default is .env
}),
],
})
export class AppModule {}
This loads environment variables from the .env
file into your application.
4. Using .env
Files for Environment Variables
Your .env
file might look like this:
iniCopyEditPORT=3000
DATABASE_URL=postgres://user:pass@localhost:5432/mydb
JWT_SECRET=supersecret
NestJS will now be able to access these values using the ConfigService
.
5. Accessing Config Values in Services
You can inject ConfigService
into any provider or controller:
tsCopyEditimport { ConfigService } from '@nestjs/config';
@Injectable()
export class AppService {
constructor(private configService: ConfigService) {}
getDatabaseUrl() {
return this.configService.get<string>('DATABASE_URL');
}
}
You can even provide defaults:
tsCopyEditthis.configService.get<number>('PORT', 3000);
6. Configuration Namespaces and Validation
To keep configuration organized, define custom configuration files as namespaces:
tsCopyEdit// config/database.config.ts
export default () => ({
database: {
host: process.env.DB_HOST,
port: parseInt(process.env.DB_PORT, 10) || 5432,
},
});
Then register it in your ConfigModule:
tsCopyEditConfigModule.forRoot({
load: [databaseConfig],
});
To validate .env
values using Joi:
tsCopyEditimport * as Joi from 'joi';
ConfigModule.forRoot({
validationSchema: Joi.object({
PORT: Joi.number().default(3000),
DATABASE_URL: Joi.string().required(),
}),
});
7. Loading Custom Config Files
You can modularize your config into separate files (e.g., auth.config.ts
, db.config.ts
) and load them all:
tsCopyEditConfigModule.forRoot({
load: [dbConfig, authConfig],
});
This keeps config organized and scalable.
8. Using ConfigService with DI
ConfigService can be injected anywhere thanks to its global scope (if set):
tsCopyEditconstructor(
private readonly configService: ConfigService
) {}
You can even inject it into factory providers or dynamic modules.
9. Config Best Practices: Security, Scoping, and Defaults
- Never commit
.env
to version control - Use
.env.example
to document required variables - Validate all config inputs
- Use default values to prevent crashes in dev
- Abstract config access via helper functions when used repeatedly
10. Example: Environment-Based Database Config
tsCopyEdit// database.providers.ts
{
provide: 'DATABASE_CONNECTION',
useFactory: async (configService: ConfigService) => {
const dbUrl = configService.get('DATABASE_URL');
return createConnection({ url: dbUrl });
},
inject: [ConfigService],
}
11. Summary and What’s Next
The @nestjs/config
package provides a powerful and flexible way to manage application configuration. It integrates deeply with NestJS’s DI system and supports validation, namespacing, and dynamic loading of config values.