@config-bound/nestjs
NestJS integration for the ConfigBound configuration library. This package provides a seamless way to integrate ConfigBound into your NestJS applications with full dependency injection support.
Installation
bash
npm install @config-bound/nestjs @config-bound/config-boundQuick Start
Basic Usage
typescript
import { Module } from '@nestjs/common';
import { ConfigBoundModule } from '@config-bound/nestjs';
import { configItem, configSection } from '@config-bound/config-bound';
import { EnvVarBind } from '@config-bound/config-bound/bind/binds/envVar';
import { z } from 'zod';
const appConfig = {
port: configItem<number>({
default: 3000,
validator: z.number().int().min(0).max(65535),
description: 'Application port'
}),
database: configSection(
{
host: configItem<string>({
default: 'localhost',
validator: z.string(),
description: 'Database host'
}),
port: configItem<number>({
default: 5432,
validator: z.number().int().min(0).max(65535),
description: 'Database port'
})
},
'Database configuration'
)
};
@Module({
imports: [
ConfigBoundModule.forRoot({
schema: appConfig,
binds: [new EnvVarBind({ prefix: 'APP' })],
validateOnInit: true,
isGlobal: true
})
]
})
export class AppModule {}Using the Service
typescript
import { Injectable } from '@nestjs/common';
import { ConfigBoundService } from '@config-bound/nestjs';
@Injectable()
export class MyService {
constructor(private readonly config: ConfigBoundService) {}
getPort(): number {
return this.config.getOrThrow('app', 'port');
}
getDatabaseUrl(): string {
const host = this.config.getOrThrow('database', 'host');
const port = this.config.getOrThrow('database', 'port');
return `postgresql://${host}:${port}`;
}
}Async Configuration
For more complex scenarios where configuration depends on other services:
typescript
import { Module } from '@nestjs/common';
import {
ConfigBoundModule,
ConfigBoundModuleOptions
} from '@config-bound/nestjs';
import { ConfigService } from '@nestjs/config';
@Module({
imports: [
ConfigBoundModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (
configService: ConfigService
): Promise<ConfigBoundModuleOptions> => {
return {
schema: appConfig,
binds: [new EnvVarBind({ prefix: 'APP' })],
validateOnInit: true
};
},
inject: [ConfigService],
isGlobal: true
})
]
})
export class AppModule {}Using a Factory Class
typescript
import { Injectable } from '@nestjs/common';
import {
ConfigBoundOptionsFactory,
ConfigBoundModuleOptions
} from '@config-bound/nestjs';
@Injectable()
export class ConfigBoundConfigService implements ConfigBoundOptionsFactory {
createConfigBoundOptions(): ConfigBoundModuleOptions {
return {
schema: appConfig,
binds: [new EnvVarBind({ prefix: 'APP' })],
validateOnInit: true
};
}
}
@Module({
imports: [
ConfigBoundModule.forRootAsync({
useClass: ConfigBoundConfigService,
isGlobal: true
})
]
})
export class AppModule {}API
ConfigBoundModule
forRoot(options: ConfigBoundModuleOptions): DynamicModule
Register the module synchronously.
Options:
schema(required): Your configuration schema. Top-level items (not in aconfigSection) are automatically placed in a section named after thenameoption (default: 'app')name(optional): Configuration name (default: 'app'). This is also the section name used for top-level config itemsbinds(optional): Array of Bind instances for value resolution. ForEnvVarBind, you can pass{ prefix: "PREFIX" }to prefix environment variable nameslogger(optional): Custom logger instancevalidateOnInit(optional): Validate configuration on module initialization (default: false)isGlobal(optional): Make the module global (default: false)
forRootAsync(options: ConfigBoundModuleAsyncOptions): DynamicModule
Register the module asynchronously.
Options:
imports(optional): Modules to importuseFactory(optional): Factory function to create optionsuseClass(optional): Class to instantiate for optionsuseExisting(optional): Existing provider to useinject(optional): Dependencies to inject into factoryisGlobal(optional): Make the module global (default: false)
ConfigBoundService
The service provides full type-safe access to your configuration:
Methods:
get(sectionName, elementName): Get a config value (returns undefined if not found)getOrThrow(sectionName, elementName): Get a config value (throws if not found)validate(): Validate all configuration valuesgetValidationErrors(): Get all validation errors without throwingaddBind(bind: Bind): Add a new bind at runtimeaddSection(section: Section): Add a new section at runtimegetSections(): Get all configuration sectionsgetTypedConfigBound(): Get the underlying TypedConfigBound instance
Properties:
name: The configuration name (string)binds: Array of Bind instances (Bind[])sections: Array of Section instances (Section[])
Best Practices
- Use
isGlobal: truefor application-wide configuration to avoid importing the module everywhere - Enable
validateOnInit: trueto catch configuration errors at startup - Use
getOrThrow()for required configuration values - Use
get()for optional configuration values with proper fallback handling - Define your schema in a separate file for reusability and better organization
- Use a prefix with
EnvVarBindto give a meaningful prefix to environment variable names (e.g.,new EnvVarBind({ prefix: "APP" })) - Remember top-level items go in the 'app' section: Top-level
configItementries are automatically placed in a section named after thenameoption (default: 'app'), so access them withconfig.getOrThrow("app", "port")
Type Safety
This package provides full TypeScript type inference from your configuration schema:
typescript
// Schema definition
const appConfig = {
port: configItem<number>({ default: 3000 }),
apiKey: configItem<string>({ default: '' })
};
// Usage with full type safety
@Injectable()
export class MyService {
constructor(private readonly config: ConfigBoundService<typeof appConfig>) {}
initialize() {
const port = this.config.get('app', 'port'); // Type: number | undefined
const key = this.config.getOrThrow('app', 'apiKey'); // Type: string
}
}License
MIT
Classes
| Class | Description |
|---|---|
| ConfigBoundModule | NestJS module for ConfigBound integration. Provides dependency injection support for ConfigBound in NestJS applications. Use forRoot() for synchronous configuration or forRootAsync() for asynchronous configuration. |
| ConfigBoundService | Injectable service that provides type-safe access to ConfigBound configuration. Wraps a TypedConfigBound instance and exposes all configuration operations for use in NestJS controllers and services. |
Interfaces
| Interface | Description |
|---|---|
| ConfigBoundModuleAsyncOptions | Async configuration options for ConfigBoundModule. Use with forRootAsync() to configure the module with dependencies from other modules. |
| ConfigBoundModuleOptions | Configuration options for ConfigBoundModule. Defines the schema, binds, and behavior for the ConfigBound integration. |
| ConfigBoundOptionsFactory | Factory interface for creating ConfigBound options asynchronously. Implement this interface when using forRootAsync({ useClass: ... }). |