wtfconfig
v2.3.0
Published
A hierarchical configuration management library for Node.js applications that supports YAML files, environment variables, and Zod schema validation.
Readme
WtfConfig
A hierarchical configuration management library for Node.js applications that supports YAML files, environment variables, and Zod schema validation.
Features
- Hierarchical configuration loading with environment-specific overrides
- Zod schema validation for configuration files with full type inference
- Variable replacement with configurable placeholders
- Multiple configuration sources: files, environment variables, and runtime configuration
- TypeScript support with automatic type inference from Zod schemas
Installation
npm install wtfconfig zodUsage
import { WtfConfigContainer } from 'wtfconfig'
import { z } from 'zod'
// Define your configuration schema with Zod
const ConfigSchema = z.object({
database: z.object({
host: z.string(),
port: z.number(),
name: z.string(),
}),
server: z.object({
port: z.number().default(3000),
host: z.string().default('localhost'),
}),
})
// Initialize with root directory and Zod schema
const configContainer = new WtfConfigContainer(
process.cwd(),
ConfigSchema,
'./config', // optional config directory
)
// Get configuration - type is automatically inferred from schema
const config = configContainer.getConfig()
// TypeScript knows the exact shape:
console.log(config.database.host) // string
console.log(config.server.port) // numberConfiguration Loading Order
The library loads configuration files in the following priority order (later files override earlier ones):
default.yamldefault-{NODE_APP_INSTANCE}.yaml(if NODE_APP_INSTANCE is set){environment}.yaml(e.g.,develop.yaml,production.yaml){environment}-{NODE_APP_INSTANCE}.yaml(if NODE_APP_INSTANCE is set)local.yamllocal-{environment}.yamllocal-{NODE_APP_INSTANCE}.yaml(if NODE_APP_INSTANCE is set)- Environment variable
NODE_CONFIG(JSON format)
Environment Variables
NODE_ENV: Determines which environment-specific config files to load (default: 'development')NODE_APP_INSTANCE: Used for instance-specific configuration filesBASE_DIR: Override the base directory for the applicationCONFIG_DIR: Override the configuration directory pathCONFIG_RC: Path to the configuration settings file (default:.configrc)NODE_CONFIG: JSON configuration to merge at runtime
Overriding Environment Variables Per-Instance
The constructor accepts an options.env map that overrides the per-key reads of
BASE_DIR, NODE_ENV, and NODE_APP_INSTANCE for that container instance.
This is useful when you want a single process to load configuration as if it
were running under a different environment, without mutating process.env.
const configContainer = new WtfConfigContainer(
process.cwd(),
ConfigSchema,
'./config',
{
env: {
NODE_ENV: 'development',
},
},
)Resolution rules apply uniformly to each of the three keys
(BASE_DIR, NODE_ENV, NODE_APP_INSTANCE):
- Key present with a string → use that value
- Key present with
null→ treat as explicitly unset (do not fall back toprocess.env) - Key absent (or
options.envitself omitted) → fall back toprocess.env[KEY]
Other environment variables (CONFIG_DIR, CONFIG_RC, NODE_CONFIG) are
always read from process.env.
Configuration Settings File
Create a .configrc file in your project root to customize paths:
{
"baseDirFromSettings": "/path/to/base",
"configDirFromSettings": "/path/to/config"
}Variable Replacement
Use [$basedir] in your YAML files to reference the base directory:
database:
path: '[$basedir]/data/app.db'Use [$env.NAME] to reference any environment variable:
database:
password: '[$env.DB_PASSWORD]'
url: '[$env.DATABASE_URL]'Env replacements respect options.env: a string value overrides
process.env[NAME], and null removes the replacer entirely (so the placeholder
is left untouched in the output). If a referenced variable is not set, the
placeholder is left unreplaced.
CLI
The package ships with a wtfconfig-get bin that prints a config value as JSON.
It loads config from the current working directory using the same hierarchy as
the library, but skips schema validation (the CLI uses z.any()).
# Read a nested value via dot-path
npx wtfconfig-get database.hostThe argument is split on . to traverse the merged config object. The value is
written to stdout as JSON.
Development
Setup
make installBuild
make buildTest
make testLint
make lintRequirements
- Node.js >= 22
License
MIT
