Environment Variables
Required
| Variable | Description |
|---|---|
DATABASE_URL | PostgreSQL connection string |
BETTER_AUTH_SECRET | Auth secret (32 hex chars): openssl rand -hex 32 |
BETTER_AUTH_URL | Your app URL |
ENCRYPTION_KEY | Encryption key (32 hex chars): openssl rand -hex 32 |
INTERNAL_API_SECRET | Internal API secret (32 hex chars): openssl rand -hex 32 |
NEXT_PUBLIC_APP_URL | Public app URL |
NEXT_PUBLIC_SOCKET_URL | Optional. WebSocket URL — defaults to the page origin; set only if realtime is on a separate host. |
AI Providers
| Variable | Provider |
|---|---|
OPENAI_API_KEY | OpenAI |
ANTHROPIC_API_KEY_1 | Anthropic Claude |
GEMINI_API_KEY_1 | Google Gemini |
MISTRAL_API_KEY | Mistral |
OLLAMA_URL | Ollama (default: http://localhost:11434) |
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, and Gemini.
In Docker, use OLLAMA_URL=http://host.docker.internal:11434 for host-machine Ollama.
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) |
vLLM (Self-Hosted)
| Variable | Description |
|---|---|
VLLM_BASE_URL | vLLM server URL (e.g., http://localhost:8000/v1) |
VLLM_API_KEY | Optional bearer token for vLLM |
OAuth Providers
| Variable | Description |
|---|---|
GOOGLE_CLIENT_ID | Google OAuth client ID |
GOOGLE_CLIENT_SECRET | Google OAuth client secret |
GITHUB_CLIENT_ID | GitHub OAuth client ID |
GITHUB_CLIENT_SECRET | GitHub OAuth client secret |
Optional
| Variable | Description |
|---|---|
API_ENCRYPTION_KEY | Encrypts stored API keys (32 hex chars): openssl rand -hex 32 |
COPILOT_API_KEY | API key for copilot features |
ADMIN_API_KEY | Admin API key for GitOps operations |
ALLOWED_LOGIN_DOMAINS | Restrict signups to domains (comma-separated) |
ALLOWED_LOGIN_EMAILS | Restrict signups to specific emails (comma-separated) |
DISABLE_REGISTRATION | Set to true to disable new user signups |
File Storage
By default Zoen 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 |
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 one provider — the mailer auto-detects in priority order: Resend → AWS SES → SMTP → Azure Communication Services → Gmail. If none are configured, emails are logged to the console instead.
| Variable | Description |
|---|---|
FROM_EMAIL_ADDRESS | Sender address (e.g. Zoen <noreply@example.com>). Falls back to noreply@EMAIL_DOMAIN. |
EMAIL_DOMAIN | Default domain when FROM_EMAIL_ADDRESS is unset |
EMAIL_VERIFICATION_ENABLED | Set to true to require email verification on signup |
Resend
| Variable | Description |
|---|---|
RESEND_API_KEY | API key from resend.com |
AWS SES
| Variable | Description |
|---|---|
AWS_SES_REGION | AWS region for SES (e.g. us-east-1). Credentials are resolved through the standard AWS SDK provider chain (env vars, IRSA, ECS/EC2 instance role, SSO). |
SMTP (works with MailHog, Postfix, SendGrid SMTP, etc.)
| Variable | Description |
|---|---|
SMTP_HOST | SMTP server hostname |
SMTP_PORT | 465 for implicit TLS, 587 for STARTTLS, 25 for plain |
SMTP_USER | Optional — omit for unauthenticated relays |
SMTP_PASS | Optional — omit for unauthenticated relays |
SMTP_SECURE | Set to true to force TLS on connect; auto-true on port 465 |
Azure Communication Services
| Variable | Description |
|---|---|
AZURE_ACS_CONNECTION_STRING | Azure Communication Services connection string |
Gmail (Google-native — GCP has no first-party transactional email service, so the native path is the Gmail API with a Google Workspace sender)
| Variable | Description |
|---|---|
GMAIL_CREDENTIALS_JSON | Inline service-account JSON. The service account needs domain-wide delegation granted for the https://www.googleapis.com/auth/gmail.send scope in the Workspace admin console |
GMAIL_SENDER | The Workspace user the service account impersonates when sending (e.g. noreply@yourdomain.com). FROM_EMAIL_ADDRESS should match this user or one of its registered aliases — Gmail rewrites unrecognized From addresses |
Alternatively, the Google Workspace SMTP relay works through the generic SMTP provider (SMTP_HOST=smtp-relay.gmail.com, port 587) with no service account required.
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.
Deployments installed with the Helm chart ship these variables preset in app.envDefaults, so chart-based installs keep enforcement unless those keys are removed or overridden.
Example .env
DATABASE_URL=postgresql://postgres:postgres@db:5432/simstudio
BETTER_AUTH_SECRET=<openssl rand -hex 32>
BETTER_AUTH_URL=https://sim.yourdomain.com
ENCRYPTION_KEY=<openssl rand -hex 32>
INTERNAL_API_SECRET=<openssl rand -hex 32>
NEXT_PUBLIC_APP_URL=https://sim.yourdomain.com
OPENAI_API_KEY=sk-...See apps/sim/.env.example for all options.