Priority order
${VAR} placeholders inside voicegw.yaml before it is parsed (below), plus a handful of settings read from a specific env var directly and bypassing the file entirely (VOICEGW_CONFIG picks which YAML file to load; VOICEGW_DB_PATH/VOICEGW_DB_URL can override cost_tracking.db_path). The DB-vs-YAML merge itself, done by ConfigManager, never looks at environment variables again.
ConfigManager
File:src/voicegateway/core/config_manager.py
ConfigManager merges the YAML config and SQLite managed rows into a single GatewayConfig.
Merge rules
YAML always takes precedence. If a provider, model, or project exists in both YAML and SQLite (matched by id), the YAML version wins:voicegw.yaml and use the dashboard or MCP for everything else, without risk of managed resources overwriting file-based config. The real merge order is projects, then providers, then models: providers merge after projects because a per-project provider row needs somewhere to land, and a managed project row arriving after a managed provider row that targets it would otherwise have nothing to nest into.
The source field
Each ProjectConfig carries a source field indicating origin:
For providers and models, the
_source key is injected into the config dict (provider_cfg above): it starts from the row’s extra_config JSON, then api_key, base_url, and _source: "db" are set on top of it, so nothing in extra_config can shadow the decrypted key.
YAML configuration
File:src/voicegateway/core/config.py
Environment variable substitution
YAML values containing${ENV_VAR} are replaced with the corresponding environment variable at load time:
Config file search
When no explicit path is provided, VoiceGateway searches in this order:VOICEGW_CONFIGenvironment variable../voicegw.yamlin the current directory.~/.config/voicegateway/voicegw.yaml./etc/voicegateway/voicegw.yaml.
Pydantic validation
File:src/voicegateway/schemas/config_schema.py
The raw YAML dict is validated against VoiceGatewayConfig before use. Validation errors include field paths and messages:
GatewayConfig dataclass
The parsed config is stored as aGatewayConfig dataclass (src/voicegateway/core/config.py):
Refresh cycle
When the dashboard or MCP server creates, updates, or deletes a managed resource, the config is refreshed without a server restart:Newly added providers and models are immediately available after the refresh. No restart needed. There is no separate router object to rebuild; the
core/router.py/core/model_id.py this page used to describe are gone, and the closest live code, core/model_resolution.py, only parses "provider/model" strings against the provider registry.Example configuration
Related pages
voicegw.yaml reference
Full YAML schema with all fields and defaults.
Environment variables
All supported environment variables and their defaults.
Storage
The SQLite tables that back managed configuration.
Security
How managed provider API keys are encrypted at rest.