English | ηΉι«δΈζ
Note: This package was previously published as
@mediaedge4tw/nest-simple-config
. It has been moved to this new location due to organizational changes.
A powerful, lightweight, and flexible configuration module for NestJS applications
Inspired by ASP.NET Core's configuration system, this module brings familiar and powerful configuration management to your NestJS applications:
π Simple & Intuitive
- Easy setup with JSON and YAML support
- Zero learning curve for developers familiar with ASP.NET Core
- Minimal dependencies and lightweight footprint
- Multiple configuration files with customizable priority
- Environment-specific configurations (dev, staging, prod)
- Flexible override system for different deployment scenarios
π³ Container-Ready
- Perfect for Docker and Kubernetes deployments
- Runtime configuration override using environment variables
- Hierarchical configuration with dot notation support
- Clear priority order: Command Line β Environment Variables β Configuration Files
- Option injection for configuration sections
- Compile-time type checking with TypeScript
- Runtime validation using class-validator decorators
π₯οΈ Command Line Support
- Command line argument parsing for dynamic configuration
- Nested configuration via dot notation (--database.host=localhost)
- Array support with indexed notation (--servers.0.name=web1)
- Runtime override with highest priority for deployment flexibility
npm i --save nest-simple-config
Create your configuration file:
appsettings.json
{
"a": "base",
"b": {
"c": 123
}
}
Import in your AppModule:
import { DynamicModule, Module } from '@nestjs/common';
import { Configuration, SimpleConfigModule } from 'nest-simple-config'
import { join } from 'path';
@Module({
imports: [
SimpleConfigModule.forRoot({
configFileOptions: {
filename: join(__dirname,'appsettings.json'),
}
})
],
})
export class AppModule {}
Inject Configuration in your services:
@Injectable()
export class OtherService {
constructor(private readonly config: Configuration) {}
getA() {
return this.config.get('a'); // got a string: 'base'
}
getC() {
return this.config.get('b.c'); // got a number: 123
}
getSection() {
return this.config.get('b'); // got a object: { c : 123}
}
}
Perfect for containerized deployments! Set environment variables to override your configuration at runtime:
# prefix is NestApp, and object path delimiter is '__'
export NestApp__a='env'
export NestApp__b__c=789
import in AppModule, and set envConfig
import { DynamicModule, Module } from '@nestjs/common';
import { Configuration, SimpleConfigModule } from 'nest-simple-config'
import { join } from 'path';
@Module({
imports: [
SimpleConfigModule.forRoot({
configFileOptions: {
filename: join(__dirname,'appsettings.json'),
},
envOptions: {
prefix: 'NestApp', // this is default value
},
})
],
})
export class AppModule {}
got override value
@Injectable()
export class OtherService {
constructor(private readonly config: Configuration) {}
getA() {
return this.config.get('a'); // got a string: 'env'
}
getC() {
return this.config.get('b.c'); // got a number: 789
}
}
β¨ New Feature: Command line argument support with the highest priority in the configuration hierarchy!
Perfect for dynamic configuration in CI/CD pipelines, Docker containers, and deployment scripts. Command line arguments automatically override both JSON configuration files and environment variables.
# Start your application with command line configuration
node dist/main.js --database.host=prod-server --database.port=5432 --debug=true
Command line arguments support nested objects using dot notation, automatically mapping to your JSON configuration structure:
appsettings.json
{
"database": {
"host": "localhost",
"port": 3306,
"credentials": {
"username": "dev",
"password": "dev123"
}
},
"server": {
"port": 3000,
"ssl": false
}
}
Command line override:
# Override nested configuration values
node dist/main.js \
--database.host=production-db \
--database.port=5432 \
--database.credentials.username=prod_user \
--database.credentials.password=secure_pass \
--server.ssl=true
Configure arrays using indexed notation:
appsettings.json
{
"servers": [],
"tags": ["default"]
}
Command line with arrays:
# Configure arrays with indexed notation
node dist/main.js \
--servers.0.name=web1 \
--servers.0.host=192.168.1.10 \
--servers.0.port=8080 \
--servers.1.name=web2 \
--servers.1.host=192.168.1.11 \
--servers.1.port=8080 \
--tags.0=production \
--tags.1=web \
--tags.2=nodejs
Result configuration:
{
"servers": [
{ "name": "web1", "host": "192.168.1.10", "port": 8080 },
{ "name": "web2", "host": "192.168.1.11", "port": 8080 }
],
"tags": ["production", "web", "nodejs"]
}
Command line configuration is automatically included when using forRoot()
:
import { Module } from '@nestjs/common';
import { SimpleConfigModule } from 'nest-simple-config';
import { join } from 'path';
@Module({
imports: [
SimpleConfigModule.forRoot({
configFileOptions: {
filename: join(__dirname, 'appsettings.json')
},
envOptions: {
prefix: 'App'
}
// Command line provider is automatically included!
})
],
})
export class AppModule {}
For advanced control, use the configuration builder:
import { Module } from '@nestjs/common';
import {
SimpleConfigModule,
JsonConfigurationProvider,
EnvConfigurationProvider,
CommandlineConfigurationProvider
} from 'nest-simple-config';
import { join } from 'path';
@Module({
imports: [
SimpleConfigModule.forRootWithConfigBuilder((builder) => {
builder
.add(new JsonConfigurationProvider(join(__dirname, 'appsettings.json')))
.add(new JsonConfigurationProvider(join(__dirname, `appsettings.${process.env.NODE_ENV}.json`), true))
.add(new EnvConfigurationProvider({ prefix: 'App' }))
.add(new CommandlineConfigurationProvider()); // Highest priority
})
],
})
export class AppModule {}
Command line arguments have the highest priority in the configuration hierarchy:
- π₯ Command Line (
--key=value
) - Highest Priority - π₯ Environment Variables (
APP__key=value
) - π₯ Configuration Files (
appsettings.json
)
@Injectable()
export class ConfigService {
constructor(private readonly config: Configuration) {}
getDatabaseHost() {
// Priority order: CLI args β ENV vars β JSON files
return this.config.get('database.host');
}
}
Command line arguments are automatically parsed with appropriate types:
# Boolean flags
node dist/main.js --debug --verbose=false --production=true
# Numeric values
node dist/main.js --port=3000 --timeout=5000 --retries=3
# String values (default)
node dist/main.js --environment=production --log-level=info
// Access parsed values with correct types
config.get('debug'); // boolean: true
config.get('verbose'); // string: "false"
config.get('production'); // string: "true"
config.get('port'); // number: 3000
config.get('timeout'); // number: 5000
config.get('environment'); // string: "production"
Choose how arrays are merged when configurations are overridden:
appsettings.json
{
"ary": [ 1, 2, 3 ]
}
appsettings.override.json
{
"ary": [ 11, 22 ]
}
import in AppModule, and set envConfig
import { DynamicModule, Module } from '@nestjs/common';
import { Configuration, SimpleConfigModule } from 'nest-simple-config'
import { join } from 'path';
@Module({
imports: [
SimpleConfigModule.forRoot({
arrayMergeMode: 'all', // 'section' or 'all'
configFileOptions: {
filename: join(__dirname,'appsettings.json'),
},
envOptions: {
prefix: 'NestApp', // this is default value
},
})
],
})
export class AppModule {}
got override array
@Injectable()
export class OtherService {
constructor(private readonly config: Configuration) {
}
// if select 'section', ary is [11, 22, 3]
// if select 'all', ary is [11, 22]
getAry() {
return this.config.get('ary');
}
}
import { DynamicModule, Module } from '@nestjs/common';
import { Configuration, SimpleConfigModule, DefaultEnvOptions
,JsonConfigurationProvider, EnvConfigurationProvider } from 'nest-simple-config'
import { join } from 'path';
@Module({
imports: [SimpleConfigModule.forRootWithConfigBuilder((builder) => {
builder.add(new JsonConfigurationProvider(join(__dirname, 'settings', 'appsettings.json')))
.add(new JsonConfigurationProvider(join(__dirname, 'settings', `appsettings.${process.env.NODE_ENV}.json`), true))
.add(new EnvConfigurationProvider({prefix: 'App'}));
})],
})
export class AppModule {}
β¨ Enhanced Feature: Enhanced type safety and validation for your configuration objects.
For applications requiring strong typing and validation, you can use typed configuration options with class-validator decorators.
First, create configuration classes with validation decorators:
// database-options.ts
import { IsString, IsInt, IsOptional, Min, Max, ValidateNested } from 'class-validator';
import { Type } from 'class-transformer';
import { BindOption } from 'nest-simple-config';
export class ConnectionPoolOptions {
@IsInt()
@Min(1)
@Max(100)
min!: number;
@IsInt()
@Min(1)
@Max(500)
max!: number;
@IsOptional()
@IsInt()
@Min(1000)
timeout?: number;
}
@BindOption('database')
export class DatabaseOptions {
@IsString()
host!: string;
@IsInt()
@Min(1)
@Max(65535)
port!: number;
@IsString()
username!: string;
@IsString()
password!: string;
@IsString()
database!: string;
@IsOptional()
@ValidateNested()
@Type(() => ConnectionPoolOptions)
pool?: ConnectionPoolOptions;
}
// server-options.ts
import { IsString, IsBoolean, IsOptional, IsInt, Min } from 'class-validator';
import { BindOption } from 'nest-simple-config';
@BindOption('server')
export class ServerOptions {
@IsString()
host!: string;
@IsInt()
@Min(1)
port!: number;
@IsOptional()
@IsBoolean()
ssl?: boolean;
@IsOptional()
@IsString()
environment?: string;
}
Create your configuration file with the corresponding structure:
// appsettings.json
{
"database": {
"host": "localhost",
"port": 5432,
"username": "admin",
"password": "secret123",
"database": "myapp",
"pool": {
"min": 5,
"max": 20,
"timeout": 30000
}
},
"server": {
"host": "0.0.0.0",
"port": 3000,
"ssl": true,
"environment": "production"
}
}
Register your typed configuration options in your module:
import { Module } from '@nestjs/common';
import { SimpleConfigModule } from 'nest-simple-config';
import { DatabaseOptions } from './config/database-options';
import { ServerOptions } from './config/server-options';
import { join } from 'path';
@Module({
imports: [
SimpleConfigModule.forRoot({
configFileOptions: {
filename: join(__dirname, 'appsettings.json')
}
}),
SimpleConfigModule.registerOptions([DatabaseOptions, ServerOptions])
],
})
export class AppModule {}
Use the @InjectConfig
decorator to inject strongly-typed configuration:
import { Injectable } from '@nestjs/common';
import { InjectConfig, Options } from 'nest-simple-config';
import { DatabaseOptions } from './config/database-options';
import { ServerOptions } from './config/server-options';
@Injectable()
export class MyService {
constructor(
@InjectConfig(DatabaseOptions) private readonly dbConfig: Options<DatabaseOptions>,
@InjectConfig(ServerOptions) private readonly serverConfig: Options<ServerOptions>
) {}
getDatabaseConnectionString(): string {
const db = this.dbConfig.value;
return `postgresql://${db.username}:${db.password}@${db.host}:${db.port}/${db.database}`;
}
getServerUrl(): string {
const server = this.serverConfig.value;
const protocol = server.ssl ? 'https' : 'http';
return `${protocol}://${server.host}:${server.port}`;
}
getDatabaseConfig(): DatabaseOptions {
return this.dbConfig.value; // Fully typed and validated
}
}
- Type Safety: Full TypeScript support with compile-time type checking
- Validation: Automatic validation using class-validator decorators
- Auto-completion: IDE support for configuration properties
- Runtime Errors: Clear error messages for invalid configurations
- Nested Objects: Support for complex nested configuration structures
We welcome contributions! If you have ideas for improvements or find any issues:
- π Report bugs by opening an issue
- π‘ Suggest features or improvements
- π§ Submit pull requests with bug fixes or new features
If you find this package helpful, please consider:
- β Star this repository on GitHub
- π’ Share it with other developers
- π¬ Report issues or ask questions in the Issues section