VibeXP is configured by a single required config.yaml. This page explains
that model and summarizes the production-critical values — it does not
duplicate every field (see
Backend Configuration for the full
list).
The config.yaml model
Section titled “The config.yaml model”At startup the backend loads one YAML file, resolved in this order:
- the
--config <path>flag, - the
VIBEXP_CONFIG_FILEenvironment variable, ./config.yamlin the working directory.
The file is required: a missing file fails fast with a message naming the expected path. String values support environment interpolation:
| Syntax | Meaning |
|---|---|
${VAR} |
The value of env var VAR (empty, with a warning, if unset). |
${VAR:-default} |
VAR when set and non-empty, otherwise default. |
$${literal} |
A literal ${literal} (the $$ escapes interpolation). |
Three files in the repo anchor the surface:
backend/config.example.yaml— the complete, commented field list, tuned for local development. Copy it to author your ownconfig.yaml.backend/config.schema.json— a JSON Schema for editor validation of the YAML.backend/config.docker.yaml— the production-neutral default baked into the published image at/app/config.yaml(withVIBEXP_CONFIG_FILEpointed at it). Every operator knob in it is a${VAR:-default}reference, so a container is configured with environment variables alone. To take full control, mount your own file over/app/config.yaml.
Must-set production values
Section titled “Must-set production values”These are the values (shown as the env vars wired in the baked image config) you must review before exposing VibeXP to the internet. Defaults are for local evaluation only.
| Env var | config.yaml key |
Why it matters |
|---|---|---|
ENCRYPTION_KEY |
security.encryption_key |
Required. Exactly 32 bytes (AES-256). Generate: openssl rand -base64 24 | cut -c1-32. |
DB_HOST / DB_PORT / DB_USER / DB_PASSWORD / DB_NAME |
database.* |
PostgreSQL connection. Change DB_PASSWORD from the default; keep it in sync with Postgres POSTGRES_PASSWORD. |
DB_SSLMODE |
database.sslmode |
disable (default) or require. Set require for managed Postgres that mandates TLS. |
SESSION_ENCRYPTION_KEY |
auth.session_encryption_key |
64 hex chars (32 bytes) backing the session cookie and OAuth state HMAC. Generate: openssl rand -hex 32. |
FRONTEND_BASE_URL |
frontend.base_url |
Your real public URL, e.g. https://<your-app-host> — the single origin serving both SPA and API. A non-localhost value automatically disables the dev-login bypass. |
OAUTH_AS_ISSUER_URL |
auth.oauth_as.issuer_url |
Public HTTPS URL enabling the embedded OAuth 2.1 Authorization Server (MCP tokens). |
MCP_RESOURCE_URI |
mcp.resource_uri |
Public MCP URL, the required token audience (RFC 8707), e.g. https://<your-app-host>/mcp/v1/common. |
INSTANCE_ADMIN_EMAILS |
auth.instance_admins |
Comma-separated emails of the root instance admins: they get the admin portal, finish first-run setup, and are the only ones who can grant the role to others (Instance Admin Portal). Set at least one before the first start. Since v0.15.0 an instance admin is also required to configure the instance’s outbound mail (Instance Email), so with this empty and no mail configured nobody can set it up. |
AUTH_SETTINGS_RECOVERY_MODE |
auth.recovery_mode |
Leave unset. Set to true only to get back in after an authentication lockout: setup mode is forced on and every start logs a new one-time SETUP URL, while the configured providers keep working. Remove it once sign-in works again. See Lockout Recovery. |
TRUSTED_PROXIES |
server.trusted_proxies |
Set if you run behind a reverse proxy or load balancer. Comma-separated CIDRs allowed to assert a client IP via X-Forwarded-For / X-Real-IP (e.g. 10.0.0.0/8,172.16.0.0/12; 192.168.1.5/32 for one host). Empty ignores those headers and uses the connecting peer, correct for a directly exposed instance. Left empty behind a proxy, per-IP rate limits collapse into one bucket and logs show the proxy address; the backend warns at startup. An invalid CIDR fails startup. |
OUTBOUND_ALLOWED_CIDRS |
security.outbound_allowed_cidrs |
Comma-separated CIDRs the SSRF guard may dial even though they are loopback or private. Empty (the default) refuses every reserved range, which is what blocks a self-hosted embedding or model sidecar on a private Docker subnet. Declare only the network your own service runs on (e.g. 172.16.0.0/12, or 127.0.0.1/32 for a same-host Ollama). Link-local (169.254.0.0/16, fe80::/10, i.e. cloud metadata) and multicast (224.0.0.0/4, ff00::/8) can never be allowlisted; a malformed CIDR or one overlapping those ranges fails startup. Local development is exempt: a localhost FRONTEND_BASE_URL already permits reserved ranges. |
Frontend runtime configuration
Section titled “Frontend runtime configuration”The SPA is embedded in the backend and served same-origin, so there is no
frontend deployment to configure. The backend serves runtime configuration at
/config.js (as window.__VIBEXP_ENV__), rendered from the frontend.*
config keys (VITE_MCP_ENDPOINT, GTM/GA4 analytics, …) — change one with an
env var and a restart, no rebuild. Never put secrets there: /config.js is
world-readable.
Company branding (name, logo, support and legal links) is not an env var. An instance admin sets it in the admin area under Settings → Site info: see Site Info (Branding).
The only frontend build-time values are deployment-neutral: the relative
VITE_API_BASE_URL=/api/v1 and the VITE_RELEASE_SHA / VITE_RELEASE_DATE
release stamps.
→ Full list: Frontend Configuration.
Backend fields
Section titled “Backend fields”The backend has many more fields than the production-critical subset above
(rate limits, retention, telemetry, …). They
live in config.yaml; config.example.yaml documents every one.
Search ranking and AI summary defaults are no longer among them. Since v0.15.0
an instance admin sets them in the admin area, under Settings → Search and
Settings → AI Summary (see
Search & AI Summary Settings).
The search: and ai_summary: sections are deprecated and only imported at
startup (see
Upgrading).
Instance email is no longer one of them. Since v0.15.0 an instance admin
configures it in the admin area, under Settings → Email (see
Instance Email). The email:
section and its environment variables (EMAIL_PROVIDER, SMTP_*, …) are
deprecated: they are imported at startup while nothing is stored and ignored
once a provider is, as described in the
upgrade note.
→ Full list: Backend Configuration.
Optional services
Section titled “Optional services”- Semantic search — embeddings run in-process; vector width is fixed at 1024. Embedding providers are configured per team in the app (model, chunk sizing, concurrency, and query/document prefixes included), not via environment.
- Model providers: per-team OpenAI-compatible LLM endpoints, also managed in the app with encrypted API keys.
- File attachments — enable the GCS emulator service and the related
appvariables. See Docker & Compose. - Scheduler: the in-process loop for recurring work; today it runs
freshness-rule evaluation. On by default. Set
SCHEDULER_ENABLED=falseto turn it off (freshness evaluation stops with it), and tune it withSCHEDULER_TICK_INTERVAL/SCHEDULER_JOB_TIMEOUT/SCHEDULER_DUE_LIMIT. See Backend Configuration.
Every running instance serves its own API spec at /openapi.yaml and
/openapi.json.