config.yaml optional as much as possible.
Prefer environment variables for normal deployments, CI, containers, and secret
injection.
Use config.yaml when you need structure that env vars cannot express cleanly,
especially:
- per-provider resilience overrides
- custom provider instance names that do not fit the generated
<provider-type>-<suffix>env naming - richer reviewable provider model lists, especially when using allowlist mode
- reviewable budget limits by
user_path - larger nested config that is easier to review in one file
<PROVIDER>_<SUFFIX>_API_KEY, <PROVIDER>_<SUFFIX>_BASE_URL, and
<PROVIDER>_<SUFFIX>_MODELS. The suffix becomes a hyphenated provider name:
OPENAI_EAST_API_KEY registers openai-east, and
OLLAMA_A_BASE_URL registers ollama-a. Azure also supports
<PROVIDER>_<SUFFIX>_API_VERSION.
Google Vertex AI follows the same suffix-to-name rule (VERTEX_US_PROJECT
registers vertex-us). Vertex project, location, and other Vertex settings
must use the same suffix for each instance: for example, pair
VERTEX_US_PROJECT with VERTEX_US_LOCATION, not the generic
VERTEX_PROJECT or VERTEX_LOCATION. VERTEX_AUTH_TYPE defaults to
gcp_adc.
Configured provider model lists can stay in env via <PROVIDER>_MODELS, for
example OPENROUTER_MODELS, ORACLE_MODELS, AZURE_MODELS, or VLLM_MODELS.
Set CONFIGURED_PROVIDER_MODELS_MODE=fallback (default) to use those lists only
when upstream /models fails or is empty, or allowlist to expose only the
configured models for providers that define a list and skip their upstream
/models calls.
Priority Order
Effective precedence is:- environment variables
- optional
config/config.yamlorconfig.yaml - built-in defaults from code
.env is not a separate priority layer. It is just a convenient way to load
environment variables before startup.
Current Schema
The current source of truth lives in the main codebase: For deployments mounted below a domain root, setserver.base_path or
BASE_PATH. For example, BASE_PATH=/g serves the gateway at /g/v1/...,
/g/admin/..., and /g/health.
To change the inbound user path header, set server.user_path_header or
USER_PATH_HEADER. The default remains X-GoModel-User-Path.
Docker
GoModel readsconfig/config.yaml first, then config.yaml.
With docker run, you can keep a host file named config.yml and mount it to
the in-container path GoModel expects:
Gotchas
Unresolved ${VAR} placeholders drop the provider
If ${OPENAI_API_KEY} appears in YAML but the env var is not actually set, the
literal string ${OPENAI_API_KEY} ends up as the API key value. The credential
filter detects the ${ substring and removes the provider entirely. This also
applies if ${VAR} appears in the middle of the value, such as
prefix-${OPENAI_API_KEY}. Always verify your env vars are exported before
starting the process, or supply a default: ${OPENAI_API_KEY:-}.
Per-provider resilience can only come from YAML
The env-var override walk skipsmap fields. RETRY_MAX_RETRIES changes the
global default for all providers but cannot target a single provider.
Per-provider tuning requires a providers.<name>.resilience: block in
config.yaml.
Partial YAML leaves the rest at defaults
YAML is unmarshalled onto a struct that has already been populated with built-in defaults. Only fields that appear in the file are written. Omittingmax_backoff from resilience.retry leaves it at its built-in default; you do
not need to repeat defaults you are happy with.