16 KiB
Environment Variables
Purpose
This document is the production-facing reference for runtime environment keys. It lists key names, ownership, placeholder expectations, and redaction rules only; it must never include live values, secret-shaped examples, connection strings, tokens, or provider credentials.
For the code-level access pattern, use docs/configuration.md. That guide defines the explicit rule that runtime entrypoints read process.env, validate and normalize values, then pass typed options into packages and handlers. For historical scan context, use docs/env-access-inventory.md; do not copy raw scan output or .env* contents into this document.
Local placeholders
Local examples may name keys but must use obvious placeholders such as <DATABASE_URL> or <MAILJET_API_KEY>. Placeholders are documentation markers, not usable credentials, and local-only files must stay out of production secret distribution.
Use placeholder-only examples when explaining required shape:
DATABASE_URL=<DATABASE_URL>
SESSION_SECRET=<SESSION_SECRET>
MAILJET_API_KEY=<MAILJET_API_KEY>
Never replace those placeholders with real secrets in docs, support notes, pull requests, screenshots, or copied CI output.
Production secret sources
Production secrets must come from CI or runtime secret stores. They must not come from docs, committed files, issue comments, chat transcripts, or copied local .env files.
The owning deployment platform should inject values at runtime. CI jobs may reference secret names, but logs and verifier output must show key names, diagnostic codes, missing/present status, or parse status only.
Required runtime keys
These keys are required for normal production application runtime unless the deployment contract explicitly scopes the runtime away from the feature that owns the key.
| Key | Owner | Purpose | Safe diagnostic surface |
|---|---|---|---|
APP_NAME |
Shared web/API/worker runtime | Human-readable product name for titles, metadata, and seeded app configuration. | Key name and configured/unconfigured status. |
DATABASE_URL |
Web/API runtime and Prisma operations | Primary application database connection. | Key name, missing/present status, migration status code. |
SESSION_SECRET |
Web/API runtime | Session signing and verification boundary. | Key name and redacted validator code only. |
APP_BASE_DOMAIN |
Split-host routing boundary | Root domain used to derive canonical app, admin, and API hosts. | Key name and host-normalization status only. |
WEB_APP_HOST |
Tenant web runtime | Canonical host for tenant app traffic, such as app.<domain>. |
Key name and host-normalization status only. |
ADMIN_APP_HOST |
Admin web runtime | Canonical host for admin traffic, such as admin.<domain>. |
Key name and host-normalization status only. |
API_HOST |
API runtime | Canonical host for versioned API traffic, such as api.<domain>. |
Key name and host-normalization status only. |
CRYPTO_SECRET |
Web/API runtime | Application encryption/signing boundary for protected data. | Key name and redacted validator code only. |
API_ACCESS_TOKEN |
Web/API runtime | Service-token boundary for internal and API operator calls. | Key name and redacted validator code only. |
JWT_SECRET |
API runtime | API session JWT signing and verification boundary. | Key name and redacted validator code only. |
ANALYTICS_TOKEN |
API runtime | Analytics ingestion and public analytics API token boundary. | Key name and redacted validator code only. |
DIRECT_URL is database-owned and may be required by Prisma or deployment-specific migration workflows. Treat it as secret material whenever present, and document only whether the key is configured for the workflow being run.
Optional integration keys
Optional integration keys are feature-gated. Missing optional keys should produce clear disabled or unavailable status, not raw value output.
| Key | Owner | Used when | Safe diagnostic surface |
|---|---|---|---|
WORKER_ENABLED |
Worker runtime | Queue processors should start for the deployment. | Boolean enablement status and diagnostic code. |
BULLMQ_REDIS_URL |
Web/API enqueue and worker runtime | Queue-backed features are enabled and need BullMQ connectivity. | Key name, missing/present status, queue readiness code. |
REDIS_URL |
Web/API enqueue and worker fallback | BULLMQ_REDIS_URL is absent and the deployment intentionally uses the generic Redis key. |
Fallback key name and readiness code only. |
MAILJET_API_KEY |
Mail provider boundary | Outbound Mailjet delivery is enabled. | Key name and redacted validator code only. |
API_KEY_LEGACY_PLAINTEXT_FALLBACK |
API-key cutover boundary | Temporary plaintext API-key lookup fallback is disabled by default; enable only during a bounded hash-backfill migration window. | Boolean status only; never record API-key material. |
MAILJET_FROM_EMAIL |
Mail provider boundary | Outbound Mailjet delivery is enabled. | Key name and sender-domain validation status only. |
MAILJET_FROM_NAME |
Mail provider boundary | A display name is needed for outbound mail. | Key name and configured/unconfigured status. |
MAILJET_SECRET_KEY |
Mail provider boundary | Outbound Mailjet delivery is enabled (Basic-Auth password paired with the public key). | Key name and redacted validator code only. |
MAILJET_WEBHOOK_SECRET |
Mail webhook boundary | Inbound Mailjet webhook Basic-Auth verification is enabled. | Key name and credential verification code only. |
STRIPE_SK |
Billing and portal boundary | Stripe billing, subscriptions, or portal integrations are enabled. | Key name, mode label, and redacted validator code only. |
STRIPE_WEBHOOK_SIGNING_SECRET |
Billing webhook boundary | Stripe webhook ingestion is enabled. | Key name and signature verification code only. |
STRIPE_ACCOUNT_COUNTRY |
Billing boundary | Stripe billing is enabled under a deployment-region policy. | Expected country label and confirmation status only. |
PORTAL_SERVER_URL |
Portal/site-builder boundary | Portal server integration is enabled. | Key name, present/missing status, and redacted URL validation code only. |
PORTAL_SERVER_FLY_TOKEN |
Portal automation boundary | Portal server automation is enabled. | Key name and redacted validator code only. |
IMPORT_QUEUE_ENABLED |
Web enqueue and worker runtime | Import jobs should be sent through BullMQ. | Boolean enablement status and diagnostic code. |
IMPORT_QUEUE_RUNTIME_READY |
Web enqueue and worker runtime | Import queue processors and scan/import services are wired end to end. | Boolean readiness status and diagnostic code. |
MISTRAL_API_KEY |
AI provider boundary | Mistral generation is enabled. | Key name and redacted provider-readiness code only. |
MISTRAL_MODEL |
AI provider boundary | Mistral generation uses a non-default model. | Model label only when approved for release records. |
AI_PROCESSING_REGION |
AI provider boundary | AI generation is enabled under a deployment-region policy. | Expected region label and confirmation status only. |
SCALEWAY_API_KEY |
AI provider boundary | Scaleway fallback generation is enabled. | Key name and redacted provider-readiness code only. |
SCALEWAY_MODEL |
AI provider boundary | Scaleway fallback uses a non-default model. | Model label only when approved for release records. |
SCALEWAY_BASE_URL |
AI provider boundary | Scaleway-compatible endpoint is configured. | Provider endpoint label or redacted URL validation code only. |
SCALEWAY_REGION |
AI provider boundary | Scaleway fallback generation is enabled. | Expected region label and confirmation status only. |
ALEPH_ALPHA_API_KEY |
AI provider boundary | Aleph Alpha fallback generation is enabled. | Key name and redacted provider-readiness code only. |
ALEPH_ALPHA_MODEL |
AI provider boundary | Aleph Alpha fallback uses a non-default model. | Model label only when approved for release records. |
ALEPH_ALPHA_BASE_URL |
AI provider boundary | Aleph Alpha-compatible endpoint is configured. | Provider endpoint label or redacted URL validation code only. |
STORAGE_PROVIDER |
Storage provider boundary | Runtime uploads should use a primary provider such as S3-compatible storage. | Provider label, configured/unconfigured status, and diagnostic code only. |
STORAGE_FALLBACK_PROVIDER |
Storage provider boundary | Runtime uploads may fall back to another configured provider. | Fallback provider label and diagnostic code only. |
STORAGE_ENDPOINT |
Storage provider boundary | S3-compatible storage is enabled. | Provider endpoint label or redacted URL validation code only. |
STORAGE_REGION |
Storage provider boundary | S3-compatible storage request signing is enabled. | Region label and configured/unconfigured status only. |
STORAGE_BUCKET |
Storage provider boundary | S3-compatible upload/download operations need a default bucket. | Bucket alias or configured/unconfigured status only; avoid customer-specific bucket names in incidents. |
STORAGE_ACCESS_KEY_ID |
Storage provider boundary | S3-compatible storage is enabled. | Key name and redacted validator code only. |
STORAGE_SECRET_ACCESS_KEY |
Storage provider boundary | S3-compatible storage is enabled. | Key name and redacted validator code only. |
STORAGE_SESSION_TOKEN |
Storage provider boundary | Temporary S3-compatible credentials are used. | Key name and redacted validator code only. |
STORAGE_PUBLIC_BASE_URL |
Storage provider boundary | A CDN or public base URL is configured for storage object URLs. | Provider endpoint label or redacted URL validation code only. |
STORAGE_FORCE_PATH_STYLE |
Storage provider boundary | The S3-compatible provider requires path-style bucket addressing. | Boolean status only. |
STORAGE_LOCAL_ROOT |
Storage provider boundary | Explicit local storage fallback is enabled for development or staging. | Key name and configured/unconfigured status only; never log filesystem contents. |
STORAGE_LOCAL_PUBLIC_BASE_URL |
Storage provider boundary | Local fallback storage needs public object URLs. | Redacted URL validation code only. |
Worker key group
WORKER_ENABLED controls whether queue processors start. Set it to true only in deployments that should run background jobs. When queue-backed web/API features enqueue jobs or workers process jobs, prefer BULLMQ_REDIS_URL for BullMQ Redis connectivity; REDIS_URL is a fallback only when BULLMQ_REDIS_URL is absent and the deployment intentionally uses the shared Redis key.
IMPORT_QUEUE_ENABLED and IMPORT_QUEUE_RUNTIME_READY must both be true before tenant import submissions enqueue jobs. Keep them disabled unless the worker runtime can process the import queue end to end.
Staging and production worker-general services must also fail loud for
outbox and workflow fanout. Set OUTBOX_DISPATCHER_ENABLED=true,
OUTBOX_DISPATCHER_REQUIRED=true, WORKFLOW_TRIGGER_OUTBOX_ENABLED=true, and
WORKFLOW_TRIGGER_OUTBOX_REQUIRED=true on worker-general together with the
workflow executor URL, API_ACCESS_TOKEN service token, and mode described in docs/worker.md. These
keys are not required on the isolated mail, import, webhook, or plugin
worker groups unless those groups explicitly take ownership of the same queue
contract in a future topology.
Each Coolify worker service must set WORKER_QUEUE_GROUP to its isolated
queue ownership (general, mail, import, webhook, or plugin) plus a
unique WORKER_HEALTH_PORT/WORKER_ADMIN_PORT pair when those ports are
exposed. The worker-mail service owns transactional mail and webhook
delivery and must set TRANSACTIONAL_MAIL_OUTBOX_REQUIRED=true in staging and
production so queued mail cannot silently pile up behind a healthy container.
Keep MARKETING_SEQUENCES_ENABLED=false until the remaining email-sequences
seed data, persisted stats aggregation, Playwright E2E, Mailjet delivery
evidence/reconciliation, scheduler/deploy evidence, and deployment record
explicitly approve production delivery.
Troubleshooting worker configuration should report queue health, enablement state, and diagnostic codes. It must not print Redis URLs, credentials, database URLs, mail tokens, job payload secrets, or customer data.
Mail key group
Mailjet outbound delivery requires MAILJET_API_KEY, MAILJET_SECRET_KEY, and MAILJET_FROM_EMAIL together (the public/secret key pair forms the Basic-Auth credential). MAILJET_FROM_NAME is optional display metadata. MAILJET_WEBHOOK_SECRET belongs to inbound webhook Basic-Auth verification and must not be confused with the outbound API key pair.
Mailjet (Sinch) hosts in the EU (Frankfurt and Belgium) by default, so there is no region-selection variable for mail; data-residency posture is a procurement/account property rather than an env toggle, and must still be backed by account/subprocessor evidence.
Diagnostics may say that a required Mailjet key is missing, a sender domain is not configured, the expected region is not confirmed, or webhook signing verification failed. They must not include API keys, signing secrets, raw webhook bodies, signatures, message contents, tenant identifiers, or real attempt identifiers.
Deployment-region provider key group
AI_PROCESSING_REGION must match the approved deployment-region policy when AI generation is enabled. The cataloged AI provider keys currently include Mistral, Scaleway, and Aleph Alpha entries; deployment records must define the allowed provider order and region labels before production traffic is routed. SCALEWAY_REGION and SCALEWAY_BASE_URL are provider-specific markers and must match the deployment record.
STRIPE_ACCOUNT_COUNTRY must match the billing account country approved for the deployment. Do not use this key to create or mutate Stripe account configuration at runtime; it is an operator-visible guardrail for deployment review and drift detection.
STRIPE_SK and STRIPE_WEBHOOK_SIGNING_SECRET are active runtime secrets. Keep them in secret stores only; never paste Stripe keys, webhook signing secrets, event payloads, or customer identifiers into docs or verification records.
Portal provider key group
PORTAL_SERVER_URL and PORTAL_SERVER_FLY_TOKEN belong to optional portal/site-builder automation. A missing portal key should make that feature unavailable with a redacted diagnostic rather than blocking unrelated core auth, tenant, admin, API, or worker boot.
Database key group
DATABASE_URL is the primary database connection key. DIRECT_URL is reserved for database and Prisma workflows that require a direct connection path. Both keys are secret material.
Database troubleshooting may reference migration status, Prisma command names, connection readiness codes, and key names. It must not include connection strings, database passwords, usernames, hosts, schemas containing customer data, or copied SQL output with sensitive records.
Redaction rules
All environment diagnostics must redact raw values. The allowed public surface is:
- environment key names;
- diagnostic codes;
- missing, present, invalid, enabled, disabled, or parsed status;
- high-level remediation text;
- CI job names and non-secret command names.
Forbidden surfaces include raw secret values, secret-shaped sample values, URLs with credentials, tokens, API keys, webhook signing secrets, Redis URLs, database URLs, customer data, and copied .env* files.
Troubleshooting
When a deployment fails because of configuration, first identify the owning runtime: web/API, worker, mail provider, webhook handler, or database operation. Then compare the reported key name and diagnostic code against this document and docs/configuration.md.
Use messages such as missing required env key DATABASE_URL, worker disabled by WORKER_ENABLED, queue config missing BULLMQ_REDIS_URL, or mail provider missing MAILJET_API_KEY. These messages are safe because they name keys and states without interpolating values.
If a fallback key is involved, state the resolution order explicitly: BULLMQ_REDIS_URL is preferred for worker Redis, and REDIS_URL is considered only when the worker runtime allows the fallback. If ambiguity remains, update the runtime configuration contract rather than adding real values to documentation.