@freakynit/configurator
v1.0.0
Published
Type-safe YAML configuration loader for Node.js with environment variable templating via Nunjucks. Supports local overrides, deep merging, caching, and customizable environment handling for clean and flexible configuration management.
Maintainers
Readme
Configuration Loader
A type-safe YAML configuration loader for Node.js with environment variable templating support using Nunjucks. Supports configuration file merging and caching for optimal performance.
Features
- Type-safe configuration loading with TypeScript generics
- YAML-based configuration files
- Nunjucks templating for environment variable interpolation
- Local configuration overrides (config.local.yaml)
- Configuration caching for improved performance
- Deep merging of configuration objects
- Built-in
defaultfilter for fallback values - Custom error handling with ConfigError
Installation
npm install "@freakynit/configurator"Quick Start
Create an example config.yaml file in your project root:
app:
name: MyApp
environment: {{ NODE_ENV | default('development') }}
port: {{ PORT | default('3000') }}
host: {{ HOST | default('localhost') }}
database:
host: {{ DB_HOST | default('localhost') }}
port: {{ DB_PORT | default('5432') }}
name: {{ DB_NAME | default('myapp_db') }}
username: {{ DB_USER | default('postgres') }}
password: {{ DB_PASSWORD | default('') }}Load your configuration:
import { getConfig } from '@freakynit/configurator';
interface AppConfig {
app: {
name: string;
environment: string;
port: number;
host: string;
};
database: {
host: string;
port: number;
name: string;
username: string;
password: string;
};
}
const config = getConfig<AppConfig>();
console.log(`Starting ${config.app.name} on port ${config.app.port}`);Usage Examples
Basic Configuration Loading
import { getConfig, ConfigError } from '@freakynit/configurator';
interface AppConfig {
app: {
name: string;
environment: string;
port: number;
};
}
try {
const config = getConfig<AppConfig>();
console.log(`Starting ${config.app.name} on port ${config.app.port}`);
console.log(`Environment: ${config.app.environment}`);
} catch (error) {
if (error instanceof ConfigError) {
console.error('Configuration error:', error.message);
if (error.cause) {
console.error('Caused by:', error.cause);
}
}
process.exit(1);
}Custom Configuration Files
const config = getConfig<AppConfig>({
configFile: 'config.production.yaml',
localConfigFile: 'config.production.local.yaml',
cache: true
});Using Custom Environment Variables
const customEnv = {
NODE_ENV: 'staging',
PORT: '9000',
DB_HOST: 'staging-db.example.com'
};
const config = getConfig<AppConfig>({
env: customEnv,
cache: false // Don't cache when using custom env
});Accessing Specific Configuration Sections
function getDatabaseConfig(): AppConfig['database'] {
const config = getConfig<AppConfig>();
return config.database;
}
const dbConfig = getDatabaseConfig();
console.log(`Database: ${dbConfig.username}@${dbConfig.host}:${dbConfig.port}`);Environment-Specific Initialization
async function initializeApp() {
const config = getConfig<AppConfig>();
if (config.app.environment === 'production') {
console.log('Initializing production environment');
// Production-specific setup
} else if (config.app.environment === 'development') {
console.log('Initializing development environment');
// Development-specific setup
}
return config;
}Configuration Reloading
import { clearConfigCache, getConfig } from '@freakynit/configurator';
function reloadConfig() {
clearConfigCache();
const newConfig = getConfig<AppConfig>();
console.log('Configuration reloaded');
return newConfig;
}Feature Flag Checking
interface AppConfig {
features: {
enableNewUI: boolean;
enableBetaFeatures: boolean;
maxUploadSize: number;
};
}
function isFeatureEnabled(feature: keyof AppConfig['features']): boolean {
const config = getConfig<AppConfig>();
return config.features[feature] as boolean;
}
if (isFeatureEnabled('enableNewUI')) {
console.log('New UI is enabled');
}Validating Required Configuration
function validateConfig(config: AppConfig): void {
const requiredKeys = [
{ path: 'app.name', value: config.app.name },
{ path: 'database.host', value: config.database.host }
];
const missing = requiredKeys.filter(key => !key.value);
if (missing.length > 0) {
throw new Error(`Missing required configuration: ${missing.map(k => k.path).join(', ')}`);
}
}
try {
const config = getConfig<AppConfig>();
validateConfig(config);
console.log('Configuration is valid');
} catch (error) {
console.error('Invalid configuration:', error);
process.exit(1);
}Local Configuration Overrides
- Create a
config.local.yamlfile to override settings without modifying the main config file. - You can use this file to keep credentials. This file is typically added to
.gitignore. - This way, each of your developers can override only the needed sections with their own test credentials without touching the main config file.
# config.local.yaml
database:
password: my-secret-password
api:
openai:
key: sk-your-api-key-hereThe local configuration is deep-merged with the base configuration, allowing partial overrides while keeping the rest of the base configuration intact.
API Reference
getConfig<T>(options?: ConfigOptions): T
Loads and parses the YAML configuration with type safety.
Parameters:
options.configFile(string, optional): Path to the base configuration file. Default:'config.yaml'options.localConfigFile(string, optional): Path to the local configuration file. Default:'config.local.yaml'options.cache(boolean, optional): Whether to cache the configuration. Default:trueoptions.env(Record<string, string>, optional): Custom environment variables for templating. Default:process.env
Returns: The parsed configuration object with type T
Throws: ConfigError if configuration files cannot be read or parsed
clearConfigCache(): void
Clears the cached configuration, forcing a reload on the next getConfig() call.
ConfigError
Custom error class for configuration-related errors.
Properties:
message: Error messagecause: Original error that caused the configuration error (if any)
Templating Syntax
The configuration loader uses Nunjucks templating with environment variables:
# Basic variable with default value
port: {{ PORT | default('3000') }}
# Variable without default (will be empty string if not set)
api_key: {{ API_KEY | default('') }}
# Boolean values
debug: {{ DEBUG | default('false') }}