packages/env in the
application repository, and read from there by three things: the check each
app runs at boot, the type of the ragen.config.ts the installer writes,
and this page. They cannot drift
from each other, which is the point — an earlier hand-written version of
this reference disagreed with the code about which S3 variables were
required.
A required variable is required once you have chosen that provider,
not in general. Everything optional has a working default in code.
Providers
One variable picks an implementation, and that choice decides what else you have to set.Storage
Chosen withSTORAGE_PROVIDER, which defaults to local.
STORAGE_PROVIDER=local
Files on the container filesystem. STORAGE_LOCAL_PATH defaults to ./data/storage, so nothing is mandatory — but every process that touches files needs the same volume.
STORAGE_PROVIDER=s3
Any S3-compatible store. S3_ENDPOINT_URL is optional — unset selects the default AWS endpoint, and it is set to point at R2, Scaleway, MinIO or Ceph. S3_SESSION_TOKEN is for temporary credentials; S3_FORCE_PATH_STYLE for stores that need path-style addressing.
Encryption
Chosen withENCRYPTION_PROVIDER. Unset auto-detects from whichever credentials are present, in the order Scaleway, KMS, local (getKeyProvider()). A deployed environment with no provider at all refuses to start, unless ALLOW_UNENCRYPTED=1 says so deliberately.
ENCRYPTION_PROVIDER=scaleway
Scaleway Key Manager (ADR-02).
ENCRYPTION_PROVIDER=kms
AWS KMS.
ENCRYPTION_PROVIDER=local
A key in the environment. Present is not the same as usable: the value is parsed by @ragenai/crypto, not here.
Reranker
Chosen withRERANK_PROVIDER, which defaults to scaleway.
RERANK_PROVIDER=scaleway
Scaleway /v1/rerank (qwen3-embedding-8b). The default. SCW_API_KEY is the same account key the Scaleway encryption provider uses — one key, two features.
RERANK_PROVIDER=cohere
Cohere Rerank v3.5, over any endpoint speaking Cohere’s /rerank shape. RERANK_COHERE_BASE_URL names it, and there is nothing to fall back to: the LITELLM_PROXY_URL default went with the proxy in B6, so selecting this variant without an endpoint reranks nothing. That failure is silent by design — an unreachable reranker degrades to no reranking rather than erroring — so set the URL deliberately and confirm reranking is happening rather than assuming it.
MAIL_PROVIDER. Unset detects from credentials: RESEND_API_KEY selects Resend, SMTP_HOST selects SMTP. With neither, outside production the message is logged instead of sent, and in production getMailProvider() throws rather than let an operator silently lose every invitation.
MAIL_PROVIDER=resend
Resend.
MAIL_PROVIDER=smtp
Any SMTP relay. Only the host is required: SMTP_PORT defaults to 587, and authentication is set only when SMTP_USER is given, because unauthenticated relays are real.
MAIL_PROVIDER=console
Log the message instead of sending it. What a laptop wants, and an explicit way to say in production that no email will be delivered — which the mailer otherwise refuses to assume.
Needs nothing else.
Speech
Chosen withSPEECH_PROVIDER. Unset leaves speech off, unless ELEVENLABS_API_KEY is set, which selects ElevenLabs. Deliberately not detected from OPENAI_API_KEY: that key is there for chat, and speech bills per request.
SPEECH_PROVIDER=elevenlabs
ElevenLabs, for both synthesis and transcription.
SPEECH_PROVIDER=openai
OpenAI’s /v1/audio/* API. Nothing is required here because SPEECH_API_KEY falls back to OPENAI_API_KEY, which a deployment reaching OpenAI already has; SPEECH_BASE_URL defaults to OpenAI itself and is how you point at vLLM or a proxy instead.
Settings
No choice to make — these are the same variables whatever else is configured.Database
Postgres.directUrl bypasses a connection pooler for migrations; without it the pooled URL is used for both.
Model gateway
Ragen calls model providers itself through@ragenai/llm-gateway (ADR-49). A route table names the upstream for each model id and credentials come per provider, so those credentials have to be present in the web, api and worker processes. The table is infra/llm-gateway/routes.yaml; LLM_ROUTES_PATH points at your own instead. There is no proxy path and no flag choosing between the two: B6 removed both, and an external gateway — Portkey, vLLM, Ollama, or a LiteLLM you run yourself — attaches as an openai-compatible route rather than as a mode.
Vector store
Qdrant, the only supported vector store (ADR-31). The URL falls back to http://localhost:6333 in code, which is why it is optional here and required outright in a deployed apps/worker — a silent fallback there once wrote every vector into a container-local Qdrant and reported success.Models
Defaults for each job. All optional: each has a fallback in code, and apps/worker requiresembeddings and vectorSize outright because its ingest cannot guess either. Changing embeddings or vectorSize after documents exist invalidates the collection.
Temporal
Document ingest runs as Temporal workflows (ADR-26). Optional here because apps/web and apps/api fall back to localhost:7233, and required outright in apps/worker, which is the process that runs them.TEMPORAL_CERT and TEMPORAL_KEY are deliberately absent: they are declared in the schema but nothing reads them yet.
Redis
Required by apps/worker, which caches organization settings through it. Genuinely optional in apps/web, where the absence is a real mode rather than a degraded one — the settings cache computes values directly, and the public chatbot rate limiter fails open, so rate limiting is off rather than enforced with a fallback limit.Observability
OpenTelemetry (ADR-22). A no-op in apps/web without an endpoint; apps/worker also traces on a Langfuse key alone.Token vault
Connector OAuth tokens and API keys (ADR-32). Each URL and its secret are all-or-nothing: a URL without its secret produces 401s rather than a legible error.
The token vault is all-or-nothing:
RAGEN_TOKEN_VAULT_URL and RAGEN_TOKEN_VAULT_SERVICE_SECRET must both be set or both omitted.
The vault is all-or-nothing: RAGEN_VAULT_URL and RAGEN_VAULT_SERVICE_SECRET must both be set or both omitted.