Environment reference
Every environment variable Tale reads at boot, the default, and the surface in the product the variable controls. The complete operator reference for `.env`.
8 min read
Tale reads its configuration from a single .env file at the repo root. About a dozen variables are mandatory at first boot; the rest tune behaviour. This page lists every variable the .env.example ships with, what it defaults to, and which surface in the product consumes it.
Groups are ordered by when you first need them: domain identity, TLS, secrets, database, instance, observability, provider encryption. If a variable changes value, restart the platform container (docker compose restart tale-platform tale-convex) for it to take effect.
How to read this page
Each group is a Name | Default | Description table. Variables marked Required must be set before docker compose up succeeds. Variables marked Optional can be left unset; the column's description names what disabling the feature does.
The .env.example file ships with inline comments that explain each variable in context; this page is the structured, grouped reference for the same set.
Domain identity (required at first boot)
| Name | Default | Description |
|---|---|---|
HOST | tale.local | Required. Hostname without protocol. Used for Docker networking and outbound email. |
SITE_URL | https://tale.local | Required. Full canonical URL including scheme and any non-standard port. Auth callbacks and external links use this. |
BASE_PATH | unset | Optional. Path prefix for subpath deployments behind a reverse proxy (e.g. /app). Leave unset for root deployments. |
The SITE_URL must match what the user types in the browser exactly. A trailing slash, a missing port, or http instead of https will break the auth callback and produce sign-in loops.
TLS
| Name | Default | Description |
|---|---|---|
TLS_MODE | selfsigned | One of selfsigned, letsencrypt, external. See TLS and domains for trade-offs. |
TLS_EMAIL | unset | Contact email for Let's Encrypt notifications. Optional but recommended in production. |
selfsigned runs Caddy with a generated cert — the browser warns, fine for development. letsencrypt requires a real domain and ports 80/443 reachable from the public Internet. external makes Caddy serve plain HTTP; an upstream reverse proxy terminates TLS.
Security secrets (required)
| Name | Default | Description |
|---|---|---|
BETTER_AUTH_SECRET | example value in shipped file | Required. Base64 secret for the Better Auth session signer. Generate with openssl rand -base64 32. Rotating invalidates every session. |
ENCRYPTION_SECRET_HEX | example value in shipped file | Required. 32-byte hex key. AES-256 key for OAuth and integration credentials and HKDF input for the guardrails secret box. Generate with openssl rand -hex 32. Rotating invalidates every DB-stored ciphertext; operators must re-enter affected secrets. |
INSTANCE_SECRET | example value in shipped file | Required. Used to derive the Convex admin key for tale deploy. Deploy fails if unset. |
Replace the values that ship in .env.example before exposing the instance — they are intentionally insecure placeholders.
Database
Tale runs two Postgres databases: the operational store (db, port 5432) behind the Convex backend, and the knowledge corpus (knowledge-db, port 5433) that holds document chunks, embeddings, and crawled pages. Both are ParadeDB and share DB_PASSWORD, but they are independent — point either at external infrastructure on its own.
| Name | Default | Description |
|---|---|---|
DB_PASSWORD | tale_password_change_me | Required. Password for the self-hosted Postgres user. Change before production. Used by both database containers. |
POSTGRES_URL | constructed from DB_PASSWORD | Optional. Override the auto-constructed operational-database URL. Use when pointing at an external Postgres or a non-standard host/port. |
KNOWLEDGE_DATABASE_URL | postgresql://tale:${DB_PASSWORD}@knowledge-db:5432/tale_knowledge | Optional. Connection URL the Convex backend uses for the knowledge corpus. Override to relocate the corpus to your own managed ParadeDB — the data-residency-sensitive store moves independently. |
KNOWLEDGE_DB_NAME | tale_knowledge | Optional. Name of the knowledge database. The bundled knowledge-db container creates this database on first boot. |
The auto-constructed operational form is postgresql://tale:${DB_PASSWORD}@db:5432. Convex expects this URL without a database name; the name is derived from the instance configuration. The knowledge corpus lives in tale_knowledge with the private_knowledge and public_web schemas; the Settings > Data residency UI writes a richer per-store config than these raw variables, covered in Data residency.
Observability
| Name | Default | Description |
|---|---|---|
SENTRY_DSN | unset | Sentry DSN for error tracking. Leave unset to disable. Compatible with self-hosted GlitchTip and Bugsink. |
SENTRY_TRACES_SAMPLE_RATE | unset | Optional sample rate for performance traces (0.0–1.0). Default behaviour depends on the deployment. |
METRICS_BEARER_TOKEN | unset | Bearer token required to access the Prometheus /metrics/* endpoints. Leave unset to keep metrics endpoints unreachable from outside. |
Setting METRICS_BEARER_TOKEN exposes two endpoints behind the token: /metrics/platform and /metrics/convex (Convex's 261 built-in metrics, which now carry the RAG and crawl timings as well). See Observability config for the scrape config.
Provider secrets encryption
| Name | Default | Description |
|---|---|---|
SOPS_AGE_KEY | unset | Inline age secret key. Encrypts providers/*.secrets.json. Default mode after tale init. Multiple keys are not supported inline. |
SOPS_AGE_KEY_FILE | unset | Path to a file with one or more age keys (one per line; # comments allowed). Required for key rotation. Mutually exclusive with the inline form. |
When both age vars are unset, Tale stores providers/*.secrets.json as plaintext JSON at mode 0600. Reach this mode only when the host disk is encrypted at rest or the files are produced by external tooling (a Kubernetes Secret mount, a Vault template). Rotating an age key is appending the new key, re-saving each provider in the UI, then dropping the old key. See Secrets with SOPS for the full rotation walk.
The env-var key source needs no environment-level switch: a provider can read its key from an environment variable instead of a secrets file, as long as the variable is named with the reserved TALE_PROVIDER_KEY_ prefix (any other name is rejected). The mechanism — the prefix gate, resolution order, the 40-character cap, the restart requirement — is documented in Providers.
Feature flags
Optional toggles for features not enabled by default. Each flag turns one feature on or off at boot; toggling requires a restart of the platform container.
| Name | Default | Description |
|---|---|---|
MICROSOFT_AUTH_ENABLED | false | Enables the Microsoft Entra sign-in option. |
TRUSTED_HEADERS_ENABLED | false | Enables the trusted-headers auth mode (identity supplied by the reverse proxy). |
FILE_EVENTS_ENABLED | false | Enables file-watching events for the OneDrive-sync integration. |
TALE_DEPLOYMENT_CONFIG_ADMINS | unset | Comma-separated email allowlist of operators allowed to edit deployment data residency. Empty/unset = read-only for all admins. |
RAG retrieval tuning
Optional knobs for knowledge-base search. The in-process RAG path (Convex node-actions) re-scores results with a cross-encoder when re-ranking is on. All carry the RAG_ prefix and are read by the platform and convex containers at boot; after changing one, run docker compose restart platform convex for it to take effect.
| Name | Default | Description |
|---|---|---|
RAG_RERANKING_ENABLED | false | Re-scores the merged BM25 + vector candidates with a cross-encoder before results are returned. Improves precision at the cost of per-query latency. |
RAG_RERANKING_MODEL | cross-encoder/ms-marco-MiniLM-L-6-v2 | Cross-encoder model identifier passed to the rerank provider. |
RAG_RERANKING_PROVIDER | local | Must be set to api to enable re-ranking — it posts the candidates to an external /rerank endpoint (Cohere/Jina-compatible). local is no longer supported and fails fast. |
RAG_RERANKING_TOP_K | 10 | Maximum number of results the reranker returns. The response never exceeds the request's own top_k. |
RAG_RERANKING_CANDIDATES | 30 | Size of the candidate pool fed to the reranker. A wider pool improves re-scoring quality and costs proportionally more time per query. |
RAG_RERANKING_API_BASE_URL | unset | Base URL for the rerank provider; the platform calls {base_url}/rerank. Required when re-ranking is enabled. |
RAG_RERANKING_API_KEY | unset | Bearer token sent to the external rerank endpoint. Leave unset for unauthenticated endpoints. |
Re-ranking ships disabled because it adds per-query latency and depends on an external endpoint. Enable it — by setting RAG_RERANKING_PROVIDER=api and pointing RAG_RERANKING_API_BASE_URL at a hosted rerank service — when retrieval precision matters more than response time. There is no in-process model to download or cache; with re-ranking off, search returns the plain merged BM25 + vector ranking.
Sessions
| Name | Default | Description |
|---|---|---|
SESSION_IDLE_TIMEOUT_MINUTES | unset | Optional. Sign a session out after this many minutes of inactivity (1–1440). The window slides on activity and is enforced server-side across email/password, SSO, and trusted-headers sessions. |
Leave it unset to keep the default session lifetime. When set, an idle session expires server-side once the window elapses, while an active one keeps sliding forward on each request. Org admins can tighten the effective window per organisation — never loosen it past this cap — via the session idle timeout governance policy; idle sessions under that policy are revoked by a sweep that runs about every five minutes.
Versioning
| Name | Default | Description |
|---|---|---|
TALE_VERSION | latest stable | The image tag pulled by docker compose pull. Pin to a specific tag for reproducible upgrades. |
Where this fits
The variables here are the operator's contact surface; the UI surface that consumes most of them lives under Platform admin. Provider keys are the one half-and-half: the keys themselves live in providers/*.secrets.json, but the UI under Settings > Providers is how you add and rotate them in practice. The next read worth queuing is Providers — it covers the file form, the SOPS modes, and the resolve-and-failover behaviour.