Environment variables

Every variable that configures a Carbon instance, grouped by concern. The source of truth is packages/env.

Carbon reads configuration from environment variables registered in packages/env. Use .env.example as the template. sst.config.ts reads infrastructure-only variables. A minimal instance requires Supabase, a session secret, and Redis; other variables enable optional features.

Core

Platform-wide behavior and edition.

CARBON_EDITIONenumoptional
One of community, cloud, enterprise, or test. Gates edition-specific features.
CONTROLLED_ENVIRONMENTbooleanoptional
Enables ITAR / controlled-environment restrictions: the US-Person certification gate, ITAR hostnames and branding, Slack and analytics disabled, and mandatory two-factor authentication that a company admin cannot turn off.
TENANT_TYPEenumoptional
single when one customer owns the deployment, as a self-hosted install does; multi (the default) for Carbon Cloud. With single, companies can send documents through the server's own mail (Server mail).
AUTH_PROVIDERSenum[]optional
Allowed sign-in methods: email, google, azure, passkey, sso (single sign-on, Enterprise edition only).
DOMAINstringoptional
Base domain the apps are served from.
ERP_URLurloptional
Public URL of the ERP app. Required for the MES: it sends shop-floor postings (material issues, completions, picking) to this address.
MES_URLurloptional
Public URL of the MES app.
DEFAULT_LANGUAGEstringoptional
Default UI language.
RATE_LIMITnumberoptional
Sign-in, MFA and unlock attempts allowed per IP every 5 minutes (default 10).

Database — Supabase

Carbon's single Postgres database. The first four are required and crash boot if missing.

SUPABASE_URLurlrequired
Supabase project URL.
SUPABASE_ANON_KEYstringrequired
Public anon key, browser-safe.
SUPABASE_SERVICE_ROLE_KEYstringrequired
Service-role key, server only, never exposed to the client.
SUPABASE_DB_URLurlrequired
Direct Postgres connection string.
SUPABASE_JWT_SECRETstringoptional
Secret used to sign and verify session JWTs. Optional to the app, but the Supabase data plane needs it, so the self-hosting recipes always generate one.

Auth & sessions

SESSION_SECRETstringrequired
Signs the session cookie. Carbon also derives its Web Push keys from it, so changing it makes each user's browser notifications re-subscribe on their next visit.
SUPABASE_AUTH_EXTERNAL_GOOGLE_CLIENT_IDstringoptional
Google OAuth client id, when google is in AUTH_PROVIDERS.
SUPABASE_AUTH_EXTERNAL_GOOGLE_CLIENT_SECRETstringoptional
Google OAuth client secret.
SUPABASE_AUTH_EXTERNAL_AZURE_CLIENT_IDstringoptional
Azure OAuth client id, when azure is enabled.
SUPABASE_AUTH_EXTERNAL_AZURE_CLIENT_SECRETstringoptional
Azure OAuth client secret.
DEV_BYPASS_EMAILstringoptional
Local only. Sign in as this email without a magic link.

Enterprise SAML single sign-on adds two more:

SAML_ENABLEDbooleanoptional
Turns on the SAML engine in the auth service.
SAML_PRIVATE_KEYstringoptional
SAML signing key — base64-encoded PKCS#1 DER RSA, minimum 2048-bit; the generation command is in .env.example.

Outside Vercel, set both CLOUDFLARE_TURNSTILE_SITE_KEY and CLOUDFLARE_TURNSTILE_SECRET_KEY to enable Cloudflare Turnstile on login forms. Without them, only per-IP rate limits and per-account lockouts apply. Set BOT_PROTECTION to turnstile, or to botid for invisible Vercel BotID protection. BotID runs only on Vercel.

Jobs & cache

REDIS_URLurlrequired
Redis connection (ioredis URL) for the permission cache and queues.
INNGEST_SIGNING_KEYstringoptional
Signs requests to the Inngest jobs runner. Required in production.
INNGEST_EVENT_KEYstringoptional
Key for sending events to Inngest. Required in production.
INNGEST_BASE_URLurloptional
Override the Inngest endpoint (self-hosted or dev).
HEADS UP

Inngest keys are required in production

INNGEST_SIGNING_KEY and INNGEST_EVENT_KEY are optional only when INNGEST_DEV=1. In other environments, the application does not start if either is missing. A self-hosted Inngest server supplies both; the Docker with Caddy recipe generates them.

The database also sends events to Inngest directly, for the event queue, search embeddings and job notifications. Whenever the ERP registers its functions with Inngest (on each deploy, and on each start of a long-running server), it also stores the address for that in the database, built from INNGEST_EVENT_KEY and INNGEST_BASE_URL, so no extra step is needed.

If the database reaches Inngest at a different address than the application does, set that address once:

sql
SELECT public.set_inngest_event_url('https://inngest.example.com/e/<event key>');

The ERP keeps the address you set and only refreshes the event key in it, so a rotated key still reaches the database on the next deploy.

Email & billing

SMTP_HOSTstringoptional
SMTP server for transactional email. Unset disables email sending.
SMTP_PORTnumberoptional
SMTP port; 465 uses implicit TLS, 587 (default) uses STARTTLS.
SMTP_USERstringoptional
SMTP username.
SMTP_PASSWORDstringoptional
SMTP password.
SMTP_FROMstringoptional
From-address for outgoing email, e.g. Carbon <no-reply@example.com>.
RESEND_API_KEYstringoptional
Optional. Resend marketing-contacts API; also a legacy SMTP fallback when SMTP_* is unset.
STRIPE_SECRET_KEYstringoptional
Stripe secret key, Cloud / Enterprise billing.
STRIPE_WEBHOOK_SECRETstringoptional
Verifies inbound Stripe webhooks.
STRIPE_CONNECT_WEBHOOK_SECRETstringoptional
Verifies inbound Stripe Connect webhooks (connected-account events, signed with a separate secret).

AI & analytics

OPENAI_API_KEYstringoptional
Powers AI features (embeddings, assist).
ANTHROPIC_API_KEYstringoptional
Anthropic key for Claude-backed features.
POSTHOG_API_HOSTurloptional
PostHog host for product analytics.
POSTHOG_PROJECT_PUBLIC_KEYstringoptional
PostHog project key.

Integrations

OAuth credentials for each connector, all optional, set only the ones you use.

XERO_CLIENT_IDstringoptional
Xero OAuth client id.
XERO_CLIENT_SECRETstringoptional
Xero OAuth client secret.
XERO_WEBHOOK_SECRETstringoptional
Verifies inbound Xero webhooks.
QUICKBOOKS_CLIENT_IDstringoptional
QuickBooks OAuth client id.
QUICKBOOKS_CLIENT_SECRETstringoptional
QuickBooks OAuth client secret.
JIRA_CLIENT_IDstringoptional
Jira OAuth client id.
JIRA_CLIENT_SECRETstringoptional
Jira OAuth client secret.
SLACK_CLIENT_IDstringoptional
Slack OAuth client id.
SLACK_CLIENT_SECRETstringoptional
Slack OAuth client secret.
SLACK_OAUTH_REDIRECT_URLurloptional
Callback for the Slack install: https://<erp-host>/api/integrations/slack/oauth. Must be registered on the Slack app. See Connect Slack.
SLACK_SIGNING_SECRETstringoptional
The Slack app's signing secret. Required: without it the Slack install ends on an error, and Carbon refuses Slack interactivity requests it cannot verify.
SLACK_STATE_SECRETstringoptional
Any long random string. Signs the state of a Slack install. Required: without it the install cannot start.
RAMP_CLIENT_IDstringoptional
Client id of the Ramp developer app. Without it the Ramp card reads Not Configured. See Connect Ramp.
RAMP_CLIENT_SECRETstringoptional
Client secret of the Ramp developer app.
ONSHAPE_CLIENT_IDstringoptional
Client id of the Onshape OAuth application for the pull integration (onshape). Without it the Onshape card reads Not Configured.
ONSHAPE_CLIENT_SECRETstringoptional
Client secret of the pull integration's Onshape OAuth application.
ONSHAPE_OAUTH_REDIRECT_URLurloptional
Callback for the pull integration: https://<erp-host>/api/integrations/onshape/oauth. Must be registered on the pull integration's Onshape application.
ONSHAPE_V2_CLIENT_IDstringoptional
Client id of the Onshape OAuth application for the panel integration (onshape-v2), a separate application from the pull integration's. Without it the Onshape V2 card reads Not Configured.
ONSHAPE_V2_CLIENT_SECRETstringoptional
Client secret of the panel integration's Onshape OAuth application.
ONSHAPE_V2_OAUTH_REDIRECT_URLurloptional
Callback for the panel integration: https://<erp-host>/api/integrations/onshape-v2/oauth. Must be registered on the panel integration's Onshape application. Without it the Onshape V2 Connect button fails with "Onshape isn't configured".
GOOGLE_CLIENT_IDstringoptional
Client id of the Google OAuth application used by the Google Calendar and Gmail workflow steps. Without it both cards read Coming soon.
GOOGLE_CLIENT_SECRETstringoptional
Client secret of that Google OAuth application.
GOOGLE_OAUTH_REDIRECT_URLurloptional
Callback for workflow integration connections: https://<erp-host>/api/integrations/connections/callback. Must be registered on the Google OAuth application.
EXCHANGE_RATES_API_KEYstringoptional
Currency exchange-rate feed.
GOOGLE_PLACES_API_KEYstringoptional
Address autocomplete.

The Onshape panel also needs an extension registered on the Onshape application and the panel's users subscribed to it — see CAD. Panel sessions and push reviews are held in Redis, so REDIS_URL is required for the panel to work.

Infrastructure — SST

Read by sst.config.ts at deploy time, not by the app.

AWS_REGIONstringrequired
Region to deploy into.
AWS_ACCOUNT_IDstringrequired
Target AWS account.
IMAGE_TAGstringrequired
ECR image tag to deploy.
CERT_ARN_ERPstringoptional
ACM certificate ARN for the ERP domain.
CERT_ARN_MESstringoptional
ACM certificate ARN for the MES domain.
URL_ERPurloptional
Custom ERP domain, overrides the default.
URL_MESurloptional
Custom MES domain, overrides the default.
HEADS UP

TRIGGER_* and UPSTASH_REDIS_* variables are obsolete. Jobs use Inngest, and the cache uses REDIS_URL.