Skip to main content
In development. 86d is being built in the open. Every capability is Experimental until it earns evidence, so check maturity levels before you rely on anything here.
A Store reads its configuration from environment variables at startup. Copy .env.example to .env in the repository root and fill in what you need. Anything commented out in .env.example is optional: uncomment it only when you turn on the Integration that reads it.
Secrets belong in the server environment. Never in config.json, never in a Template, never in a NEXT_PUBLIC_ variable unless the value is genuinely public.

The three you have to set

Nothing works until these are right, and production refuses to start without a usable auth secret.
In production BETTER_AUTH_SECRET has to be at least 32 characters, must not be a known repository or Better Auth default, and must carry enough character variety to pass an entropy check. Development and test fall back to a local-only value when it is absent, and production rejects that fallback outright.

Where your Store lives

Store identity and managed access

86D_STORE_ID, 86D_API_URL, and 86D_WORKLOAD_CREDENTIAL travel together. Set one without the others and managed configuration resolution fails rather than guessing. When all three are present, a failed exchange, a rejected credential, or a network error stops the boot: the runtime does not quietly fall back to a local Template and serve the wrong Store.
Human sign-in uses its own OAuth client. No machine credential can authenticate a person, and no person’s session can act as the workload. Keep workload credentials and OAuth client secrets out of browser code, logs, agent output, Templates, and merchant-readable settings. See managed identity and authentication.

How Integrations turn on

Setting the right variables is what enables most Integrations. 86d generate reads your environment and writes the wiring into the generated API. Miss one variable in a set and the Integration stays off, silently, because a half-configured provider is worse than none. Every group below is an and: all the listed variables have to be present.

Payments

Configure one sandbox provider at a time. There is no safe failover between payment providers: a refund has to go back through whichever provider took the money. See Set up a payment provider.

Shipping, tax, and delivery

Sales channels

Messaging

.env.example lists TWILIO_PHONE_NUMBER and TWILIO_SERVICE_SID, but the generator reads TWILIO_FROM_NUMBER for the sending number. Set TWILIO_FROM_NUMBER if you want outbound SMS to have a from address.

Search and AI

AI_GATEWAY picks which upstream handles AI calls: 86d, openai, gemini, openrouter, or vercel. GEMINI_API_KEY is read when you point it at Gemini.

Analytics and error reporting

The Analytics Module turns on when any one of NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID, GA4_MEASUREMENT_ID, or SENTRY_DSN is set. Google Tag Manager and GA4 are Third-party Analytics you own and configure. Sentry is Store Runtime diagnostics. Neither is authoritative for Orders, Payments, Inventory, Loyalty, revenue, or GMV. When those numbers disagree, the database is right.

Storage

Full setup is in Configure storage.

Seed and Docker values

Railway supplies RAILWAY_PUBLIC_DOMAIN, RAILWAY_PROJECT_ID, RAILWAY_SERVICE_ID, and RAILWAY_ENVIRONMENT_ID at runtime. Use the first to build your public URL: APP_URL=https://$RAILWAY_PUBLIC_DOMAIN.

Variables that are reserved and do nothing

.env.example lists social login variables that the current auth package does not read. Setting them enables nothing. See Authentication for what does work today.