Configuration Sources
A source produces a partial config object. Multiple sources merge; the union is what your app sees.
The shapes below are the actual ConfigSource union from
@omnitron-dev/titan/module/config:
type ConfigSource =
| IFileConfigSource
| IEnvironmentConfigSource
| IArgvConfigSource
| IObjectConfigSource
| IRemoteConfigSource;
Five built-in source types
File — JSON / YAML / TOML / INI / .env
{
type: 'file',
path: 'config/default.yaml',
format?: 'json' | 'yaml' | 'toml' | 'ini' | 'env', // auto-detected if omitted
encoding?: 'utf8',
transform?: (data) => data,
optional?: false,
}
Reads a file on startup. Format is auto-detected from extension if
format is not specified.
Environment variables
{
type: 'env',
prefix?: 'APP_',
separator?: '__', // for nested paths
transform?: 'lowercase' | 'uppercase' | 'camelCase' | (key, value) => any,
}
Env vars matching prefix become config keys. APP_DATABASE__URL
becomes database.url when separator: '__'.
Argv
{
type: 'argv',
prefix?: '--app-',
}
Reads command-line flags.
Inline object
{
type: 'object',
data: { port: 3000, debug: true },
}
Note data (not value). A literal object; useful for defaults
that don't warrant a file.
Remote HTTP
{
type: 'remote',
url: 'https://config.internal/my-app',
headers?: { Authorization: 'Bearer …' },
timeout?: 5_000,
retry?: 3,
}
Fetches config from a URL. Periodic re-fetch is implementation-
defined; check the ConfigLoaderService source for current
behaviour.
Source ordering
Sources merge in the order listed (deep merge — later wins per leaf key):
sources: [
{ type: 'object', data: { db: { url: 'localhost', pool: { max: 10 } } } },
{ type: 'env', prefix: 'APP_' }, // APP_DB__URL=prod-db
]
// Result: { db: { url: 'prod-db', pool: { max: 10 } } }
You can also assign explicit priority on the base IConfigSource
when natural order is awkward.
Conventional source layout
A common pattern:
ConfigModule.forRoot({
schema: AppConfigSchema,
sources: [
{ type: 'file', path: 'config/default.yaml' },
{ type: 'file', path: 'config/local.yaml', optional: true },
{ type: 'env', prefix: 'APP_' },
],
})
default.yaml— checked into git, sane defaults.local.yaml— git-ignored, developer overrides.APP_*env vars — production secrets, dynamic infra params.
Environment-specific files (production.yaml, etc.) can be loaded
by adding an extra source whose path is computed at startup from
your app's environment detection.
Custom sources
Provide your own loader by extending ConfigLoaderService or
implementing IConfigSource plus a registration shim. The source
interface and loader are in
@omnitron-dev/titan/module/config/config-loader.service.ts.
Anti-patterns
- Secrets in files committed to git.
config/default.yamlshould not contain production secrets. Use env vars or a secret manager. - Dynamic config paths from user input. A config-injection vulnerability. Use only static paths or values from trusted sources.
- Big monolithic config. A 500-line
default.yamlis hard to reason about. Split into per-domain files and load them individually.
→ Next: Validation.