Environment variables

Configure variables in the env files or secret strategy for your deployment. Restart source processes or recreate containers/pods after changes; a running process does not reread credentials.

Production Compose derives DATABASE_URL and BETTER_AUTH_URL on its service definitions, overriding values in .env. Use POSTGRES_* and NEXT_PUBLIC_APP_URL there. Helm constructs the database URL from its database values. See Docker and Kubernetes secret strategies.

Required

VariableDescription
DATABASE_URLPostgreSQL connection string
BETTER_AUTH_SECRETAuth secret, at least 32 characters: openssl rand -hex 32. Must be identical on the app and realtime services
BETTER_AUTH_URLYour app URL — must be the real public origin, not localhost
ENCRYPTION_KEYEncryption key, exactly 64 hex characters (32 bytes): openssl rand -hex 32
INTERNAL_API_SECRETInternal API secret, at least 32 characters: openssl rand -hex 32
NEXT_PUBLIC_APP_URLPublic app URL

openssl rand -hex 32 prints 64 hex characters. Encryption keys require that format. The app skips its env schema validation; individual consumers can reject invalid values when first used. Realtime validates BETTER_AUTH_SECRET and INTERNAL_API_SECRET at boot and rejects values shorter than 32 characters.

Retain ENCRYPTION_KEY and API_ENCRYPTION_KEY across upgrades and restores. There is no supported in-place key rotation procedure; losing a key makes values encrypted with it unreadable — workspace and personal environment variables, stored provider API keys, MCP OAuth credentials, and deployment/chat secrets in the first case, user-generated Sim API keys in the second. Back them up separately from the database.

VariableDescription
API_ENCRYPTION_KEYEncrypts stored Sim API-key material; use exactly 64 hex characters (openssl rand -hex 32). When unset, legacy API keys can be stored in plain text; the key getter logs a warning when called
CRON_SECRETBearer token for the background job endpoints: openssl rand -hex 32. Required whenever background jobs are enabled — the Helm chart's default, and the chart will not render without it, unless it comes from app.secrets.existingSecret or External Secrets. See Background jobs
REDIS_URLRedis connection string. Required for cross-replica events and features with no fallback, such as CLI pairing approval. Some single-process storage paths can fall back to PostgreSQL or local state; see Redis
REDIS_TLS_SERVERNAMETLS SNI override. Required when REDIS_URL uses rediss:// with a bare IP, or the app throws the first time it opens a Redis connection
NEXT_PUBLIC_SOCKET_URLPublic WebSocket URL. Proxied deployments default to the page origin; a localhost page uses port 3002. Set it for a separate realtime host.
TRUSTED_ORIGINSComma-separated additional origins to trust for auth (apex + www, alias domains)
AUTH_TRUSTED_PROXIESComma-separated reverse-proxy IPs/CIDRs so the client IP cannot be forged through X-Forwarded-For
INTERNAL_API_BASE_URLInternal URL for server-side self-calls, e.g. http://sim-app.simstudio.svc.cluster.local:3000. Defaults to the public base URL. The Trigger.dev worker ignores it and uses the public app URL.
SIM_MCP_URLPublic URL of the Sim MCP server when you serve it on its own host, e.g. https://mcp.example.com/mcp. Point that host at the app; Sim serves only the MCP endpoint and its OAuth metadata there, and stops serving /api/mcp on the app host so clients use one URL. Optional — defaults to <NEXT_PUBLIC_APP_URL>/api/mcp
DATABASE_REPLICA_URLRead-replica connection string for log listing, audit logs, and dashboard aggregations. Falls back to the primary when unset

AI providers

VariableProvider
OPENAI_API_KEYOpenAI — also the default knowledge base embedding provider
ANTHROPIC_API_KEY_1Anthropic Claude
GEMINI_API_KEY / GEMINI_API_KEY_1Google Gemini
MISTRAL_API_KEYMistral
XAI_API_KEY_1xAI
KIMI_API_KEY_1Moonshot Kimi
TYPESAFE_API_KEY_1 / _2 / _3TypeSafe Jev hosted key rotation
ZAI_API_KEY_1Z.ai
TOGETHER_API_KEYTogether AI
FIREWORKS_API_KEYFireworks AI
BASETEN_API_KEYBaseten
COHERE_API_KEYCohere — required for the Knowledge block reranker
OLLAMA_URLOllama (default: http://localhost:11434)
VERTEX_PROJECT / VERTEX_LOCATIONGoogle Vertex AI — GCP project ID and region (region defaults to us-central1)

Knowledge bases use an embedding model independent of the chat model. See Knowledge bases for supported providers, local Ollama, and vector widths.

For provider-key rotation, configure _1, _2, and _3 keys, such as OPENAI_API_KEY_1 and OPENAI_API_KEY_2. OpenAI, Anthropic, Gemini, xAI, Kimi, Z.ai, Cohere, and Fireworks support numbered keys.

For Ollama on the Docker host, use OLLAMA_URL=http://host.docker.internal:11434 and ensure its server is reachable from the container.

Agent tool-call depth. An Agent block keeps calling tools until the model answers, with no round-trip limit by default. With billing disabled there is also no execution timeout unless EXECUTION_TIMEOUT_FREE (sync) or EXECUTION_TIMEOUT_ASYNC_FREE (async) is set, so a looping agent keeps making paid model calls. Set MAX_TOOL_ITERATIONS (for example MAX_TOOL_ITERATIONS=50) to cap the model round trips per block, or set those timeouts to bound the whole run.

Catalog visibility

VariableDescription
BLACKLISTED_PROVIDERSComma-separated provider IDs to hide from the model pickers, e.g. openai,anthropic
BLACKLISTED_MODELSComma-separated model names or prefixes to hide, e.g. gpt-4,claude-*
PREVIEW_BLOCKSComma-separated preview block types to reveal, e.g. gmail_v2. Empty or unset hides every preview block

AWS Bedrock

VariableDescription
NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALSSet true when using the AWS default credential chain (IAM roles, ECS task roles, IRSA). Hides credential fields in the Agent block UI

Azure OpenAI

VariableDescription
AZURE_OPENAI_API_KEYAzure OpenAI API key
AZURE_OPENAI_ENDPOINTAzure OpenAI endpoint URL
AZURE_OPENAI_API_VERSIONAPI version supported by your Azure model/deployment; check the API lifecycle
KB_OPENAI_MODEL_NAMEAzure deployment name serving the knowledge base embedding model. Optional — defaults to the model id, which is only correct when the deployment is named after the model

Azure Anthropic

VariableDescription
AZURE_ANTHROPIC_ENDPOINTAzure Anthropic service endpoint URL
AZURE_ANTHROPIC_API_KEYAzure Anthropic API key
AZURE_ANTHROPIC_API_VERSIONAPI version (e.g., 2023-06-01)

Document OCR

VariableDescription
OCR_PROVIDERPDF OCR backend: local, mistral, or azure-mistral. Leave it unset and Sim picks the first provider whose credentials are present, falling back to the local parser
OCR_AZURE_ENDPOINTAzure Mistral OCR endpoint URL
OCR_AZURE_API_KEYAzure Mistral OCR API key
OCR_AZURE_MODEL_NAMEAzure Mistral OCR model name

Self-hosted OpenAI-compatible endpoints

VariableDescription
VLLM_BASE_URLOpenAI-compatible vLLM or LM Studio URL. Both the server root (http://localhost:8000) and versioned API URL (http://localhost:8000/v1) are accepted
VLLM_API_KEYOptional bearer token for the vLLM or LM Studio endpoint
LITELLM_BASE_URLLiteLLM proxy base URL
LITELLM_API_KEYOptional bearer token for LiteLLM

Knowledge bases

VariableDescription
KB_IMAGE_EXTRACTION_MODELGemini model that reads Confluence image attachments into searchable text. Defaults to gemini-3.8-flash; a value that is not a Gemini 3 or later model in the catalog falls back to the default. Needs GEMINI_API_KEY (or a workspace Gemini key); without one, image attachments are left out of syncs
KB_IMAGE_EXTRACTIONS_PER_SYNCNew or changed images one connector sync run sends for reading, at least 1. Defaults to 500; the rest wait for the next sync, which reports as partial. With member accounts, each continuation run can read up to this many
KB_CONFIG_VISION_REQUESTS_PER_MINUTEImage reads per minute per Gemini key, shared by every sync on the deployment. Defaults to 300; lower it to match a key with a smaller Gemini quota
KB_EMBEDDING_MODELEmbedding model for new knowledge bases. Defaults to text-embedding-3-small; use ollama/<model> for a model on your own Ollama. An unrecognised hosted model id falls back to the default, but an ollama/ id is taken at face value — if that model is not on the server, knowledge-base creation fails rather than falling back
EMBEDDING_OUTPUT_DIMSStored vector width: 384, 768, 1024, 1536, or 3072. Hosted models default to 1536 when supported, otherwise their largest storable width. Invalid hosted widths fall back with a warning; Ollama can infer its actual width when unset
OPENROUTER_API_KEYFallback route for the OpenAI embedding models — used when it is set and OPENAI_API_KEY is not the chosen path
COHERE_API_KEYEnables the Knowledge block reranker

KB_EMBEDDING_MODEL and EMBEDDING_OUTPUT_DIMS apply to new knowledge bases. Existing bases retain their recorded model and width, and bases with different settings cannot be searched together.

For hosted models, Sim checks catalog-supported widths and falls back to the model's default on invalid configuration. For Ollama, leave EMBEDDING_OUTPUT_DIMS unset to infer the model's width; creation fails if Sim cannot establish a supported width. If you set it explicitly, a mismatch can fail document processing. Example pairings:

EMBEDDING_OUTPUT_DIMSWorks with
384ollama/all-minilm
768ollama/nomic-embed-text, ollama/embeddinggemma, text-embedding-3-small, gemini-embedding-001
1024ollama/mxbai-embed-large, ollama/bge-m3, text-embedding-3-small, text-embedding-3-large
1536text-embedding-3-small, text-embedding-3-large, gemini-embedding-001
3072text-embedding-3-large, gemini-embedding-001

For Compose or a source checkout, run bunx sim-setup add knowledge-embeddings to choose OpenAI, Azure OpenAI, OpenRouter, Gemini, or Ollama and write its configuration. The three OpenAI-family transports share model/width choices. bunx sim-setup config reports the family selected by KB_EMBEDDING_MODEL. For Helm, set the variables through chart values or your secret strategy. Run Ollama yourself; the setup command configures a connection, not an Ollama installation.

The Embeddings block reads the same OLLAMA_URL. It lists the models on that server that report an embedding capability, with the width each one emits where Ollama reports it, so a workflow can embed locally without an API key. Ollama only began reporting capabilities in 0.5 — against an older server nothing can be filtered, so the list includes chat models and labels none of them with a width. Check what you pick there, or upgrade Ollama.

Login providers

Google, GitHub, and Microsoft sign-in, their callback URLs, and the DISABLE_*_AUTH switches are documented in Authentication.

Integration credentials

OAuth integrations require a provider application and its credentials on a self-hosted deployment. API-key integrations use the keys supplied in their blocks. The full table, redirect-URI format, and setup steps are in Integrations and OAuth.

Access control

Who may sign up and sign in — the allowlists, blocklists, DISABLE_REGISTRATION, DISABLE_INVITATIONS, DISABLE_PUBLIC_API, and DISABLE_AUTH — is documented in Authentication.

Code execution

VariableDescription
SANDBOX_PROVIDERRemote sandbox provider: e2b (default) or daytona
E2B_ENABLED / E2B_API_KEYEnable E2B remote execution
DAYTONA_API_KEYDaytona API key (used when SANDBOX_PROVIDER=daytona)
E2B_FUNCTION_TEMPLATE_IDImmutable <template>:<build-id> ref for the Function base image. Required for E2B; a mutable tag is refused
E2B_FUNCTION_TEMPLATE_GENERATIONMonotonic release generation printed by the same build. Required for E2B
DAYTONA_FUNCTION_SNAPSHOT_IDImmutable snapshot ID (not a name) for the Function base image. Required for Daytona
E2B_PI_TEMPLATE_ID / DAYTONA_PI_SNAPSHOT_IDThe image Pi runs on. Separate from the Function base — configuring the provider and Function image alone leaves Pi failing closed
SANDBOXES_ENABLED / NEXT_PUBLIC_SANDBOXES_ENABLEDEnable custom sandbox entitlement through deployment configuration where supported; see the enterprise guide for billing-mode requirements. Neither is sufficient on its own — a provider key and an immutable Function base must also be configured. Set the NEXT_PUBLIC_ twin only after the server side works; it enables nothing by itself — it reveals the Function block's Sandbox selector, and on a Compose install or source checkout bunx sim-setup doctor confirms it agrees with the selected provider's readiness
IVM_MAX_EXECUTIONS_PER_WORKERExecutions before an isolated-vm worker is recycled
IVM_MAX_BROKERS_PER_EXECUTIONHost-call brokers per execution
IVM_MAX_BROKER_ARGS_JSON_CHARSMax argument payload size
IVM_MAX_BROKER_RESULT_JSON_CHARSMax result payload size

Plain JavaScript without imports runs in isolated-vm within Node child workers in the app container. Python, Shell, imported JavaScript, sandbox/file-path execution, and Pi require the corresponding remote provider and image configuration. See Sandboxes for the base-image build and Security for the isolation comparison.

Chat and PII

VariableDescription
COPILOT_API_KEYAPI key for the default Sim service. Required for Chat, the Sim Chat workflow block, and Inbox operations that use that service
NEXT_PUBLIC_CHAT_DISABLEDSet to true to hide the Chat module: the workspace lands on your first workflow, with no chats list or editor Chat panel. Chat is shown when unset; bunx sim-setup sets it for you if you skip the chat key
PII_URLBase URL of the Presidio service backing PII detection and redaction. The Helm chart wires it to its own pii Service when pii.enabled; on Compose point it at the PII service on your network. Local development and the Helm fallback use http://localhost:5001; that address works only when the service is reachable there. Point production at a running service to use redaction
ADMIN_API_KEYAdmin API key for GitOps operations and organization provisioning

Enterprise features

On standard billing-disabled self-hosted deployments, configuration enables enterprise features. Per-feature flags override the suite switch. Billing-enabled deployments also have plan/entitlement gates; see Self-hosted enterprise features.

VariableDescription
ENTERPRISE_ENABLED, NEXT_PUBLIC_ENTERPRISE_ENABLEDEnable the whole enterprise feature set
SSO_ENABLED, NEXT_PUBLIC_SSO_ENABLEDEnable SAML and OIDC single sign-on on its own. See Authentication
SSO_SKIP_DOMAIN_VERIFICATIONSkip the DNS challenge when an administrator clicks Verify on a domain. Off by default; self-hosted only. Trusts administrator claims for SSO and SCIM across the instance. See Verified domains
SCIM_ENABLED, NEXT_PUBLIC_SCIM_ENABLEDEnable directory provisioning on its own. Needs SSO. See Directory provisioning
INSTANCE_ORG_NAMEName of the organization every user joins automatically at signup
INSTANCE_ORG_SLUGSlug for that organization (derived from the name when omitted)
INSTANCE_ORG_OWNER_EMAILOwner of that organization (defaults to the first user to sign up)

Most enterprise features read their settings from the organization that owns a workspace, so enabling the flags alone is not enough — the deployment also needs an organization model. See the self-hosted enterprise guide for the per-feature flags, both organization patterns, and the Admin API.

File storage

By default Sim writes uploads to local disk. Neither stock production Compose nor the default Helm chart mounts the upload directory, so configure cloud storage or a persistent local layout before retaining files. See Object storage for the full setup, bucket layout, and IAM policy.

VariableDescription
AWS_REGIONAWS region — set with S3_BUCKET_NAME to enable S3
AWS_ACCESS_KEY_IDAWS access key. Omit to use the instance/IRSA credential chain
AWS_SECRET_ACCESS_KEYAWS secret key. Omit to use the instance/IRSA credential chain
STORAGE_PROVIDERSelects the backend explicitly: local, s3, azure, or gcs. Unset means the first fully configured backend wins
S3_BUCKET_NAMEGeneral workspace files bucket — set with AWS_REGION to enable S3
AZURE_STORAGE_CONTAINER_NAMEGeneral files container — set with Azure credentials to enable Blob (takes precedence over S3)
AZURE_CONNECTION_STRINGAzure connection string, or use AZURE_ACCOUNT_NAME + AZURE_ACCOUNT_KEY
GCS_BUCKET_NAMEGeneral workspace files bucket — enables GCS when neither Azure Blob nor S3 is configured
GCS_PROJECT_IDGCP project ID. Omit to infer from credentials/ADC
GCS_CREDENTIALS_JSONInline service-account JSON. Omit to use Application Default Credentials (Workload Identity, GOOGLE_APPLICATION_CREDENTIALS)

Email providers

Configure at least one. Every configured provider stays active and is tried in order — Resend → AWS SES → SMTP → Azure Communication Services → Gmail — falling through only on failure. With none configured, mail is silently not sent. The variables for each provider, plus setup, verification, and troubleshooting, are in Email.

Networking and execution limits

VariableDefaultDescription
API_MAX_JSON_BODY_BYTES50 MiBConfigured JSON body cap; contract-validated routes clamp it to 10 MiB, or a lower route cap
CHAT_MAX_REQUEST_BYTES220 MiBConfigured body cap on the public deployed-chat endpoint; the Next.js proxy buffer also applies
WEBHOOK_MAX_REQUEST_BYTES10 MiBMax body on public webhook receiver endpoints
WORKFLOW_EXECUTION_CONCURRENCY_LIMIT75Trigger.dev workflow task concurrency
WEBHOOK_EXECUTION_CONCURRENCY_LIMIT75Trigger.dev webhook task concurrency
SCHEDULE_EXECUTION_CONCURRENCY_LIMIT30Deployment-wide active scheduled executions in the default database-backed mode; Trigger.dev uses a separate task queue
RESUME_EXECUTION_CONCURRENCY_LIMIT50Trigger.dev resume task concurrency
EGRESS_ALLOWED_HOSTSunsetComma-separated hostnames outbound requests may reach on a private network. Leading wildcard allowed, e.g. host.docker.internal,*.svc.cluster.local. Not honored for URLs harvested from content or a third-party response, nor for an HTTP block's proxyUrl
EGRESS_ALLOWED_IP_RANGESunsetComma-separated CIDRs or IPs outbound requests may reach on a private network, e.g. 10.0.0.0/8. Same exclusions
ALLOW_PRIVATE_DATABASE_HOSTSunsetDeprecated. Vouches for the entire private address space, for database, cache, and mail connector hosts only. Replace it with the two settings above naming specific destinations

A malformed entry in either allowlist stops the app at startup with a message naming the setting. See the SSRF boundary for the accepted syntax and for what the allowlist does and does not reach.

Most /api routes also pass through Next.js Proxy, which buffers only the first 10 MiB with the current app configuration. Raising these variables or an external proxy limit does not raise that buffer. See Request size limits for the layers to configure.

Limits

With BILLING_ENABLED disabled, hosted-plan execution rates/timeouts and table/storage quotas are not enforced unless you set their free-tier variables. Independent protocol, body-size, concurrency, and security rate limits still apply. Billing-enabled deployments enforce their plan limits. Keep BILLING_ENABLED and NEXT_PUBLIC_BILLING_ENABLED consistent so enforcement and the UI agree.

Retention cleanup is separately opt-in through DATA_RETENTION_ENABLED or the enterprise suite. A configured retention policy still applies without billing; see Data retention.

VariableOpts inSuggested value
RATE_LIMIT_FREE_SYNCSync executions per minute50
RATE_LIMIT_FREE_ASYNCAsync executions per minute200
RATE_LIMIT_FREE_API_ENDPOINTv1 API endpoint requests per minute30
EXECUTION_TIMEOUT_FREESync execution timeout (seconds)300
EXECUTION_TIMEOUT_ASYNC_FREEAsync execution timeout (seconds)5400
FREE_TABLES_LIMITMax user tables per workspace5
FREE_TABLE_ROWS_LIMITMax rows per user table50000
FREE_STORAGE_LIMIT_GBFile storage quota (GiB)5

Without billing, accounts resolve to the free tier for these counters. Each explicit free-tier variable enables only its corresponding limit.

Current stock Compose and Helm configuration do not preset these free-tier caps. Charts before 1.5.0 did; inherited values can still reach upgraded pods.

Remove an inherited limit

If a limit remains after upgrading, inspect the pod's configuration for inherited values, such as FREE_TABLES_LIMIT or FREE_TABLE_ROWS_LIMIT from a chart older than 1.5.0 or your own values file. On Helm, remove the key by overriding it with null:

app:
  envDefaults:
    FREE_TABLES_LIMIT: null
    FREE_TABLE_ROWS_LIMIT: null

Setting the variable to an empty string does not remove it: the chart reads an empty value as "not specified", so the inherited value still applies.

Null the variable in every layer that sets it. If it appears in both app.env and app.envDefaults, nulling only the app.env entry lets the envDefaults value apply again and the limit stays in force. With External Secrets, also drop the key from externalSecrets.remoteRefs.app, which keeps syncing it independently. Confirm what the pod will actually receive before rolling out:

helm template sim oci://ghcr.io/simstudioai/charts/sim --version 1.11.8 -f values.yaml | grep -A1 FREE_TABLE   # expect no output

null deletion has no effect under helm upgrade --reuse-values — pass your full values with -f, or use --reset-then-reuse-values (Helm 3.14+). If you deploy with Argo CD, put the null in valueFiles or the values string rather than valuesObject, which strips nulls. On Docker Compose, delete the line from your .env file.

Observability

VariableDescription
OTEL_EXPORTER_OTLP_ENDPOINTOTLP collector endpoint
OTEL_EXPORTER_OTLP_HEADERSAuth headers, key=value comma-separated
OTEL_TRACES_SAMPLER_ARGTrace sampling ratio
OTEL_DEPLOYMENT_ENVIRONMENTEnvironment label on emitted spans
TELEMETRY_SAMPLING_RATIOApplication-level sampling ratio
TELEMETRY_ENDPOINTWhere anonymous telemetry is sent. Defaults to https://telemetry.simstudio.ai/v1/traces — point it at your own collector to keep traces internal
NEXT_TELEMETRY_DISABLEDSet to 1 to disable anonymous telemetry entirely
GRAFANA_OTLP_ENDPOINT / GRAFANA_OTLP_HEADERS / GRAFANA_DEPLOYMENT_ENVIRONMENTGrafana Cloud OTLP export

See Observability.

Example .env

# App/source-checkout example: replace placeholders before use.
# Production Compose derives its DSN from POSTGRES_* instead.
DATABASE_URL=postgresql://<user>:<password>@<host>:5432/simstudio?sslmode=require
NEXT_PUBLIC_APP_URL=https://sim.yourdomain.com
BETTER_AUTH_URL=https://sim.yourdomain.com

# Secrets — generate each with `openssl rand -hex 32`
BETTER_AUTH_SECRET=<openssl rand -hex 32>
ENCRYPTION_KEY=<openssl rand -hex 32>
INTERNAL_API_SECRET=<openssl rand -hex 32>
API_ENCRYPTION_KEY=<openssl rand -hex 32>
CRON_SECRET=<openssl rand -hex 32>

# Coordination (required past one replica)
REDIS_URL=redis://redis:6379

# Models — OPENAI_API_KEY also powers knowledge base embeddings
OPENAI_API_KEY=sk-...

# Email
RESEND_API_KEY=re_...
FROM_EMAIL_ADDRESS="Sim <noreply@yourdomain.com>"

# Access control
ALLOWED_LOGIN_DOMAINS=yourdomain.com

This is an app/source-checkout example, not a replacement for the Compose setup or Helm values. See apps/sim/.env.example for additional options.