Required
| Variable | Description |
|---|---|
DATABASE_URL | PostgreSQL connection string |
BETTER_AUTH_SECRET | Auth secret, at least 32 characters: openssl rand -hex 32. Must be identical on the app and realtime services |
BETTER_AUTH_URL | Your app URL — must be the real public origin, not localhost |
ENCRYPTION_KEY | Encryption key, exactly 64 hex characters (32 bytes): openssl rand -hex 32 |
INTERNAL_API_SECRET | Internal API secret, at least 32 characters: openssl rand -hex 32 |
NEXT_PUBLIC_APP_URL | Public app URL |
openssl rand -hex 32 prints 64 hex characters. ENCRYPTION_KEY and API_ENCRYPTION_KEY must be exactly that — a value of any other shape throws the first time Sim encrypts or decrypts, not at startup. The rest are secrets of no fixed shape and only need 32 characters or more. The Sim app never checks — it runs its env schema with validation skipped — but the realtime service validates BETTER_AUTH_SECRET and INTERNAL_API_SECRET at boot and refuses to start if either is shorter.
ENCRYPTION_KEY and API_ENCRYPTION_KEY cannot be rotated or recovered. Losing either makes the data it protects permanently 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.
Strongly recommended
| Variable | Description |
|---|---|
API_ENCRYPTION_KEY | Encrypts user-generated Sim API keys at rest, exactly 64 hex characters (32 bytes): openssl rand -hex 32. When unset, API keys are stored in plain text — the app logs a warning each time it encrypts or decrypts one and keeps working |
CRON_SECRET | Bearer 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_URL | Redis connection string. Optional on a single replica; required past one app or realtime replica — see Redis |
REDIS_TLS_SERVERNAME | TLS 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_URL | WebSocket URL — defaults to the page origin; set only if realtime is on a separate host |
TRUSTED_ORIGINS | Comma-separated additional origins to trust for auth (apex + www, alias domains) |
AUTH_TRUSTED_PROXIES | Comma-separated reverse-proxy IPs/CIDRs so the client IP cannot be forged through X-Forwarded-For |
INTERNAL_API_BASE_URL | Internal URL for server-side self-calls, e.g. http://sim-app.simstudio.svc.cluster.local:3000. Optional — falls back to the public base URL. Deliberately ignored inside the Trigger.dev worker runtime, where a cluster-internal address resolves to the worker itself |
DATABASE_REPLICA_URL | Read-replica connection string for log listing, audit logs, and dashboard aggregations. Falls back to the primary when unset |
AI Providers
| Variable | Provider |
|---|---|
OPENAI_API_KEY | OpenAI — also the default knowledge base embedding provider |
ANTHROPIC_API_KEY_1 | Anthropic Claude |
GEMINI_API_KEY / GEMINI_API_KEY_1 | Google Gemini |
MISTRAL_API_KEY | Mistral |
XAI_API_KEY_1 | xAI |
KIMI_API_KEY_1 | Moonshot Kimi |
ZAI_API_KEY_1 | Z.ai |
TOGETHER_API_KEY | Together AI |
FIREWORKS_API_KEY | Fireworks AI |
BASETEN_API_KEY | Baseten |
COHERE_API_KEY | Cohere — required for the Knowledge block reranker |
OLLAMA_URL | Ollama (default: http://localhost:11434) |
VERTEX_PROJECT / VERTEX_LOCATION | Google Vertex AI — GCP project ID and region (region defaults to us-central1) |
Knowledge bases need an embedding model, selected with KB_EMBEDDING_MODEL. Hosted: text-embedding-3-small (default) and text-embedding-3-large on OpenAI or Azure OpenAI, and gemini-embedding-001 on Gemini. Local: any embedding model on your own Ollama, named ollama/<model> (for example ollama/nomic-embed-text) with OLLAMA_URL set. Ollama serves embeddings only through this variable — embeddings never route through the configured chat model, so vLLM and LM Studio do not substitute.
For load balancing, add multiple keys with _1, _2, _3 suffixes (e.g., OPENAI_API_KEY_1, OPENAI_API_KEY_2). Works with OpenAI, Anthropic, Gemini, xAI, Kimi, Z.ai, Cohere, and Fireworks.
In Docker, use OLLAMA_URL=http://host.docker.internal:11434 for host-machine Ollama.
Agent tool-call depth. An Agent block ends its run after 20 model round trips of tool calling. Raise the ceiling with MAX_TOOL_ITERATIONS (for example MAX_TOOL_ITERATIONS=50). Every extra iteration is another model call, so raise it deliberately.
Catalog visibility
| Variable | Description |
|---|---|
BLACKLISTED_PROVIDERS | Comma-separated provider IDs to hide from the model pickers, e.g. openai,anthropic |
BLACKLISTED_MODELS | Comma-separated model names or prefixes to hide, e.g. gpt-4,claude-* |
PREVIEW_BLOCKS | Comma-separated preview block types to reveal, e.g. gmail_v2. Empty or unset hides every preview block |
AWS Bedrock
| Variable | Description |
|---|---|
NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS | Set true when using the AWS default credential chain (IAM roles, ECS task roles, IRSA). Hides credential fields in the Agent block UI |
Azure OpenAI
| Variable | Description |
|---|---|
AZURE_OPENAI_API_KEY | Azure OpenAI API key |
AZURE_OPENAI_ENDPOINT | Azure OpenAI endpoint URL |
AZURE_OPENAI_API_VERSION | API version (e.g., 2024-02-15-preview) |
KB_OPENAI_MODEL_NAME | Azure 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
| Variable | Description |
|---|---|
AZURE_ANTHROPIC_ENDPOINT | Azure Anthropic service endpoint URL |
AZURE_ANTHROPIC_API_KEY | Azure Anthropic API key |
AZURE_ANTHROPIC_API_VERSION | API version (e.g., 2023-06-01) |
Document OCR
| Variable | Description |
|---|---|
OCR_PROVIDER | PDF 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_ENDPOINT | Azure Mistral OCR endpoint URL |
OCR_AZURE_API_KEY | Azure Mistral OCR API key |
OCR_AZURE_MODEL_NAME | Azure Mistral OCR model name |
Self-hosted OpenAI-compatible endpoints
| Variable | Description |
|---|---|
VLLM_BASE_URL | OpenAI-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_KEY | Optional bearer token for the vLLM or LM Studio endpoint |
LITELLM_BASE_URL | LiteLLM proxy base URL |
LITELLM_API_KEY | Optional bearer token for LiteLLM |
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 & 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
| Variable | Description |
|---|---|
SANDBOX_PROVIDER | Remote sandbox provider: e2b (default) or daytona |
E2B_ENABLED / E2B_API_KEY | Enable E2B remote execution |
DAYTONA_API_KEY | Daytona API key (used when SANDBOX_PROVIDER=daytona) |
E2B_FUNCTION_TEMPLATE_ID | Immutable <template>:<build-id> ref for the Function base image. Required for E2B; a mutable tag is refused |
E2B_FUNCTION_TEMPLATE_GENERATION | Monotonic release generation printed by the same build. Required for E2B |
DAYTONA_FUNCTION_SNAPSHOT_ID | Immutable snapshot ID (not a name) for the Function base image. Required for Daytona |
E2B_PI_TEMPLATE_ID / DAYTONA_PI_SNAPSHOT_ID | The 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_ENABLED | Enable custom sandboxes on a self-hosted deployment, bypassing the hosted-plan requirement. 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 npx sim-setup doctor confirms it agrees with the selected provider's readiness |
IVM_MAX_EXECUTIONS_PER_WORKER | Executions before an isolated-vm worker is recycled |
IVM_MAX_BROKERS_PER_EXECUTION | Host-call brokers per execution |
IVM_MAX_BROKER_ARGS_JSON_CHARS | Max argument payload size |
IVM_MAX_BROKER_RESULT_JSON_CHARS | Max result payload size |
Without a remote provider, user code runs in an in-process V8 isolate inside the app container. See Sandboxes for the base-image build and Security for the isolation comparison.
Networking & Limits
| Variable | Default | Description |
|---|---|---|
API_MAX_JSON_BODY_BYTES | 50 MB | Max JSON body on contract-validated API routes |
CHAT_MAX_REQUEST_BYTES | 220 MB | Max body on the public deployed-chat endpoint |
WEBHOOK_MAX_REQUEST_BYTES | 10 MB | Max body on public webhook receiver endpoints |
WORKFLOW_EXECUTION_CONCURRENCY_LIMIT | 75 | Trigger.dev workflow task concurrency |
WEBHOOK_EXECUTION_CONCURRENCY_LIMIT | 75 | Trigger.dev webhook task concurrency |
SCHEDULE_EXECUTION_CONCURRENCY_LIMIT | 30 | Scheduled executions per app instance |
RESUME_EXECUTION_CONCURRENCY_LIMIT | 50 | Trigger.dev resume task concurrency |
EGRESS_ALLOWED_HOSTS | unset | Comma-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_RANGES | unset | Comma-separated CIDRs or IPs outbound requests may reach on a private network, e.g. 10.0.0.0/8. Same exclusions |
ALLOW_PRIVATE_DATABASE_HOSTS | unset | Deprecated. 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.
Your reverse proxy's body-size limit must be at least as large as the app limits above. See Networking.
Observability
| Variable | Description |
|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT | OTLP collector endpoint |
OTEL_EXPORTER_OTLP_HEADERS | Auth headers, key=value comma-separated |
OTEL_TRACES_SAMPLER_ARG | Trace sampling ratio |
OTEL_DEPLOYMENT_ENVIRONMENT | Environment label on emitted spans |
TELEMETRY_SAMPLING_RATIO | Application-level sampling ratio |
TELEMETRY_ENDPOINT | Where anonymous telemetry is sent. Defaults to https://telemetry.simstudio.ai/v1/traces — point it at your own collector to keep traces internal |
NEXT_TELEMETRY_DISABLED | Set to 1 to disable anonymous telemetry entirely |
GRAFANA_OTLP_ENDPOINT / GRAFANA_OTLP_HEADERS / GRAFANA_DEPLOYMENT_ENVIRONMENT | Grafana Cloud OTLP export |
See Observability.
Knowledge Bases
| Variable | Description |
|---|---|
KB_EMBEDDING_MODEL | Embedding 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_DIMS | Vector width new knowledge bases are stored at: 384, 768, 1024, 1536 (default), or 3072. It must be a width the chosen model can emit; anything else falls back to 1536 with a warning |
OPENROUTER_API_KEY | Fallback route for the OpenAI embedding models — used when it is set and OPENAI_API_KEY is not the chosen path |
COHERE_API_KEY | Enables the Knowledge block reranker |
Both variables apply at creation time and are recorded on the knowledge base, so changing either affects new knowledge bases only. Existing ones keep the model and width they were built with, and knowledge bases with different settings cannot be searched together.
Matching the width to the model is yours to get right for a hosted provider: Sim knows only the
widths each one documents, so a width that model cannot emit falls back to 1536 with a warning.
For Ollama it is checked — leave EMBEDDING_OUTPUT_DIMS unset and Sim reads the model's width from
your server, refusing to create the knowledge base if it cannot; set it explicitly and a mismatch
surfaces as a failed document instead. Common pairings:
EMBEDDING_OUTPUT_DIMS | Works with |
|---|---|
384 | ollama/all-minilm |
768 | ollama/nomic-embed-text, ollama/embeddinggemma, text-embedding-3-small, gemini-embedding-001 |
1024 | ollama/mxbai-embed-large, ollama/bge-m3, text-embedding-3-small, text-embedding-3-large |
1536 | text-embedding-3-small, text-embedding-3-large, gemini-embedding-001 |
3072 | text-embedding-3-large, gemini-embedding-001 |
On a Compose install or source checkout, sim-setup add knowledge-embeddings walks through all of
this — pick OpenAI, Azure OpenAI, OpenRouter, Gemini, or Ollama and it writes the variables that
family needs. The three OpenAI-family transports share the same model and width prompts.
sim-setup config then reports the one family your KB_EMBEDDING_MODEL actually selects, rather
than every provider you happen to hold a key for. Helm releases set these values through your own
chart values instead, and an Ollama server is yours to run either way — sim-setup configures Sim
to reach one, never installs it.
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.
Chat & PII
| Variable | Description |
|---|---|
COPILOT_API_KEY | API key for Chat. Without it the Sim Chat block, scheduled prompt jobs, and Inbox cannot run |
NEXT_PUBLIC_CHAT_DISABLED | Set to true to hide the Chat module: the workspace lands on your first workflow, with no chats list, scheduled tasks, or editor Chat panel. Chat is shown when unset; npx sim-setup sets it for you if you skip the chat key |
PII_URL | Base 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. The default http://localhost:5001 exists only in local development, and leaving it makes redaction fail |
DURABLE_SECRET_PROVENANCE_ENFORCED_SURFACES | Durable stores where a value whose secret provenance was never recorded fails the run instead of logging a warning. all, or a comma-separated subset of memory, table-row, knowledge, workspace-file. Unset (nothing enforced) by default |
ADMIN_API_KEY | Admin API key for GitOps operations and organization provisioning |
Enterprise Features
Enterprise features are unlocked by configuration rather than billing on self-hosted deployments. One switch turns on the full set; per-feature flags below it override the switch either way.
| Variable | Description |
|---|---|
ENTERPRISE_ENABLED, NEXT_PUBLIC_ENTERPRISE_ENABLED | Enable the whole enterprise feature set |
SSO_ENABLED, NEXT_PUBLIC_SSO_ENABLED | Enable SAML and OIDC single sign-on on its own. See Authentication |
SCIM_ENABLED, NEXT_PUBLIC_SCIM_ENABLED | Enable directory provisioning on its own. Needs SSO. See Directory provisioning |
INSTANCE_ORG_NAME | Name of the organization every user joins automatically at signup |
INSTANCE_ORG_SLUG | Slug for that organization (derived from the name when omitted) |
INSTANCE_ORG_OWNER_EMAIL | Owner 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. For production, point it at AWS S3, Azure Blob, or Google Cloud Storage. See Object Storage for the full setup, bucket layout, and IAM policy.
| Variable | Description |
|---|---|
AWS_REGION | AWS region — set with S3_BUCKET_NAME to enable S3 |
AWS_ACCESS_KEY_ID | AWS access key. Omit to use the instance/IRSA credential chain |
AWS_SECRET_ACCESS_KEY | AWS secret key. Omit to use the instance/IRSA credential chain |
STORAGE_PROVIDER | Selects the backend explicitly: local, s3, azure, or gcs. Unset means the first fully configured backend wins |
S3_BUCKET_NAME | General workspace files bucket — set with AWS_REGION to enable S3 |
AZURE_STORAGE_CONTAINER_NAME | General files container — set with Azure credentials to enable Blob (takes precedence over S3) |
AZURE_CONNECTION_STRING | Azure connection string, or use AZURE_ACCOUNT_NAME + AZURE_ACCOUNT_KEY |
GCS_BUCKET_NAME | General workspace files bucket — enables GCS when neither Azure Blob nor S3 is configured |
GCS_PROJECT_ID | GCP project ID. Omit to infer from credentials/ADC |
GCS_CREDENTIALS_JSON | Inline 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.
Limits
Self-hosted deployments (billing disabled) run without plan limits: no rate limits, no execution timeouts, no table or storage caps, and no retention-based data deletion. Each limit can be opted back in individually by explicitly setting its variable.
| Variable | Opts in | Suggested value |
|---|---|---|
RATE_LIMIT_FREE_SYNC | Sync executions per minute | 50 |
RATE_LIMIT_FREE_ASYNC | Async executions per minute | 200 |
RATE_LIMIT_FREE_API_ENDPOINT | v1 API endpoint requests per minute | 30 |
EXECUTION_TIMEOUT_FREE | Sync execution timeout (seconds) | 300 |
EXECUTION_TIMEOUT_ASYNC_FREE | Async execution timeout (seconds) | 5400 |
FREE_TABLES_LIMIT | Max user tables per workspace | 5 |
FREE_TABLE_ROWS_LIMIT | Max rows per user table | 50000 |
FREE_STORAGE_LIMIT_GB | File storage quota (GB) | 5 |
Without billing, every account resolves to the free tier, so only the free-tier variables apply. Setting one variable enforces only that limit — the rest stay unlimited.
Neither deployment presets these. The Helm chart previously did, which enforced hosted-plan caps on self-hosted installs; chart 1.5.0 removed the presets so Compose and Kubernetes behave identically.
Removing a limit you already inherited
If a limit is still enforced after upgrading — most often a FREE_TABLES_LIMIT or FREE_TABLE_ROWS_LIMIT carried forward from a chart older than 1.5.0, or copied into your own values file — the variable is still reaching the pod. On Helm, remove it by overriding it with null:
app:
envDefaults:
FREE_TABLES_LIMIT: null
FREE_TABLE_ROWS_LIMIT: nullSetting 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.9.5 -f values.yaml | grep -A1 FREE_TABLE # expect no outputnull 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.
Example .env
# Core
DATABASE_URL=postgresql://postgres:postgres@db:5432/simstudio
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.comSee apps/sim/.env.example for all options.