Environment variables
Complete reference for every environment variable used across Prood applications.
Prood uses a single root .env.local file for local development. Run pnpm env:link to generate ignored apps/*/.env.local files; it copies the root file and writes the local one-domain URLs shown below into each app.
One domain
Production is one domain, https://prood.com, with a path per app: /dashboard, /admin, /pay, /docs, and /v1, /mcp, /api/auth and /.well-known/agent-configuration for the API. apps/web is the gateway that rewrites those paths to each app's own Vercel project (see Deployment). Merchant stores stay on {store}.prood.app.
Locally, run every app and open the gateway at http://localhost:3001, so the apps share one origin. The apps listen on 3002 (dashboard), 3003 (docs), 3004 (checkout), 3005 (api) and 3006 (admin).
Two kinds of address appear below:
- Public URLs: what a browser sees. They point at the gateway:
https://prood.comin production andhttp://localhost:3001locally, with/dashboard,/adminor/payon the end where noted. - Internal URLs: server-to-server calls (
NEXT_PUBLIC_AUTH_URL,COMMERCE_API_URL). They point straight at the API app: its*.vercel.appaddress in production,http://localhost:3005locally.
Database
| Variable | Required | Used by | Description |
|---|---|---|---|
DATABASE_URL | Yes | All apps | Neon Postgres connection string. Shared by commerce data (@prood/platform) and Better Auth tables. |
DATABASE_URL="postgresql://user:password@host/db?sslmode=require"Multi-tenancy
| Variable | Required | Used by | Description |
|---|---|---|---|
NEXT_PUBLIC_PLATFORM_DOMAIN | Prod | Storefront, Dashboard, API | Apex for merchant storefront subdomains only ({slug}.prood.app). Platform services run on prood.com. Example: prood.app. |
Storage
| Variable | Default | Description |
|---|---|---|
S3_ENDPOINT | — | S3-compatible endpoint (R2, AWS, MinIO) |
S3_BUCKET | — | Bucket name |
S3_ACCESS_KEY_ID | — | Access key |
S3_SECRET_ACCESS_KEY | — | Secret key |
S3_PUBLIC_URL | — | Public URL for uploaded assets (required for S3) |
Files uploaded through uploadForTenant() are namespaced per tenant: org/<orgId>/….
Authentication (Better Auth)
| Variable | Required | Used by | Description |
|---|---|---|---|
BETTER_AUTH_SECRET | Yes | API, dashboard, admin, storefront | Session signing secret. Generate: openssl rand -base64 32 |
AUTH_PROXY_SECRET | Prod | API, dashboard, admin | Dashboard and admin send it in a header next to the client address they pass to the API. The API believes that address only when the secret matches, and keys auth rate limits on it. Use the same value on all three. Required in production. Generate: openssl rand -base64 32 |
BETTER_AUTH_URL | Yes | API, dashboard, admin | Public origin of the auth issuer, which is the gateway: https://prood.com (locally http://localhost:3001). Do not set it on the storefront, which infers its origin per store. |
NEXT_PUBLIC_AUTH_URL | Yes | Dashboard, admin | Internal origin their server-side auth proxies forward sign-in/sign-up/org ops to: the API project's own address, http://localhost:3005 locally. No browser calls it. |
NEXT_PUBLIC_WEB_URL | Yes | API, dashboard, docs, web | The marketing site and gateway: https://prood.com (locally http://localhost:3001). |
NEXT_PUBLIC_DASHBOARD_URL | Yes | API, dashboard, docs, web | Merchant dashboard URL, with its path: https://prood.com/dashboard (locally http://localhost:3001/dashboard). |
NEXT_PUBLIC_ADMIN_URL | Yes | API, admin | Platform admin URL, with its path: https://prood.com/admin (locally http://localhost:3001/admin). |
NEXT_PUBLIC_API_URL | Yes | Dashboard, docs, web | Public origin of the REST API, which the gateway serves: https://prood.com (locally http://localhost:3001). |
NEXT_PUBLIC_STOREFRONT_URL | Yes | API, dashboard, storefront | Storefront apex, e.g. https://prood.app. Stores are its subdomains, so never a single store's host. |
AUTH_COOKIE_DOMAIN | No | API | Leave it unset. The dashboard, admin console and API share one host, so the session cookie is already shared. The code still reads it and, if set, shares the cookie across subdomains of that domain, which nothing needs. |
PASSKEY_RP_ID | Optional | API, dashboard, admin | The domain passkeys belong to: prood.com in production, localhost locally. Set it together with PASSKEY_ORIGINS, or leave both empty to keep passkeys off. It can't be a *.vercel.app address. |
PASSKEY_ORIGINS | Optional | API, dashboard, admin | The exact origins that may use passkeys, comma separated, with no path: https://prood.com in production, http://localhost:3001 locally. Each must be the ID or a subdomain of it. |
Prood doesn't remember devices, so there is no trusted-device cookie or setting: the two-factor code is asked for at every sign-in.
The gateway
Set on the prood-web project only. Each is the origin of an app's own Vercel project, with no path. A build on Vercel fails when one is missing. Locally they default to the ports shown and can stay unset.
| Variable | Required | Receives | Local default |
|---|---|---|---|
DASHBOARD_ORIGIN | On Vercel | /dashboard | http://localhost:3002 |
ADMIN_ORIGIN | On Vercel | /admin | http://localhost:3006 |
DOCS_ORIGIN | On Vercel | /docs, /api/search | http://localhost:3003 |
CHECKOUT_ORIGIN | On Vercel | /pay | http://localhost:3004 |
API_ORIGIN | On Vercel | /v1, /mcp, /api/auth, /.well-known/agent-configuration | http://localhost:3005 |
Seed credentials
| Variable | Description |
|---|---|
ADMIN_EMAIL | Initial platform admin email (used by pnpm db:seed) |
ADMIN_PASSWORD | Initial platform admin password |
Payments
There are no payment environment variables. Each store connects its own account in the dashboard, under Integrations, and the credentials are stored encrypted in integration_config. See Payment integration.
Checkout app
| Variable | Required | Description |
|---|---|---|
CHECKOUT_URL | Yes | Public base URL of apps/checkout, including its /pay path: https://prood.com/pay in production, http://localhost:3001/pay through the local gateway. Storefront calls its API and redirects here after order placement, and the payment return and webhook URLs are built from it. |
CHECKOUT_API_SECRET | Yes | Shared secret between storefront and checkout. Sent as x-checkout-secret header. Generate: openssl rand -base64 32 |
COMMERCE_API_URL | Yes | Internal API base, with /v1, for webhook forwarding: the API project's own address in production. Default: http://localhost:3005/v1 |
Upstash Redis
| Variable | Required | Used by | Description |
|---|---|---|---|
KV_REST_API_URL | Checkout, production auth | apps/checkout, apps/api, apps/storefront | Redis REST endpoint for checkout sessions and auth rate limits |
KV_REST_API_TOKEN | Checkout, production auth | apps/checkout, apps/api, apps/storefront | Redis REST token |
Checkout sessions (@prood/checkout-host) are persisted in Redis with a configurable TTL. Without Redis, the checkout app cannot create or load sessions. The API and the storefront each keep their auth rate limits in the same Redis, because serverless instances don't share memory. Without it they count in memory, which is fine locally and not in production.
Dashboard (Vercel domains)
Optional for local dev; required for custom domain provisioning in production:
| Variable | Description |
|---|---|
VERCEL_TOKEN | Vercel API token |
STOREFRONT_VERCEL_PROJECT_ID | Storefront Vercel project ID. Do not use Vercel's injected VERCEL_PROJECT_ID; it points at the current project, not necessarily the storefront. |
VERCEL_TEAM_ID | Vercel team ID (if applicable) |
Commerce API
| Variable | Default | Description |
|---|---|---|
COMMERCE_API_URL | http://localhost:3005/v1 | Internal base URL for @prood/api-client in storefront and dashboard: the API project's own address, with /v1 |
API_PUBLIC_URL | http://localhost:3001 | Public API origin for Agent Auth OpenAPI proxy and discovery: https://prood.com in production |
TRUST_PROXY | false | Set true behind a reverse proxy for JWT aud validation |
Integration encryption
| Variable | Description |
|---|---|
INTEGRATION_ENCRYPTION_KEY | Yes |
Marketing site
| Variable | Description |
|---|---|
NEXT_PUBLIC_DOCS_URL | Origin the docs are served from. The docs live at {origin}/docs: https://prood.com in production, http://localhost:3001 through the local gateway |
Per-app summary
| App | Critical vars |
|---|---|
| web | NEXT_PUBLIC_WEB_URL, NEXT_PUBLIC_DOCS_URL, NEXT_PUBLIC_DASHBOARD_URL, NEXT_PUBLIC_API_URL, and the five *_ORIGIN variables on Vercel |
| storefront | DATABASE_URL, COMMERCE_API_URL, BETTER_AUTH_SECRET, KV_REST_API_*, CHECKOUT_URL, CHECKOUT_API_SECRET |
| dashboard | DATABASE_URL, COMMERCE_API_URL, BETTER_AUTH_SECRET, AUTH_PROXY_SECRET, NEXT_PUBLIC_AUTH_URL, BETTER_AUTH_URL, NEXT_PUBLIC_DASHBOARD_URL, CHECKOUT_URL, INTEGRATION_ENCRYPTION_KEY, PASSKEY_* (optional) |
| checkout | KV_REST_API_*, CHECKOUT_API_SECRET, COMMERCE_API_URL |
| api | DATABASE_URL, BETTER_AUTH_*, AUTH_PROXY_SECRET, KV_REST_API_*, NEXT_PUBLIC_*_URL, API_PUBLIC_URL, PASSKEY_* (optional), storage keys, CHECKOUT_API_SECRET, INTEGRATION_ENCRYPTION_KEY, RESEND_* |
| admin | DATABASE_URL, BETTER_AUTH_SECRET, AUTH_PROXY_SECRET, BETTER_AUTH_URL, API_PUBLIC_URL, NEXT_PUBLIC_AUTH_URL, NEXT_PUBLIC_ADMIN_URL, PASSKEY_* (optional) |
| docs | NEXT_PUBLIC_WEB_URL, NEXT_PUBLIC_DOCS_URL, NEXT_PUBLIC_DASHBOARD_URL, NEXT_PUBLIC_API_URL (OpenAPI synced at build time) |
Production checklist
- Generate strong secrets:
BETTER_AUTH_SECRET,AUTH_PROXY_SECRET,CHECKOUT_API_SECRET,INTEGRATION_ENCRYPTION_KEY - Configure
NEXT_PUBLIC_PLATFORM_DOMAINfor subdomain tenants Set the one-domain URLs, the gateway's five*_ORIGINvariables onprood-web, andPASSKEY_RP_ID=prood.comwithPASSKEY_ORIGINS=https://prood.com. LeaveAUTH_COOKIE_DOMAINunset - Provision Upstash Redis for checkout and auth rate limits, and set
KV_REST_API_*on API, storefront and checkout - Set
RESEND_API_KEYand a verified-domainRESEND_FROM_EMAIL - Run
pnpm db:migrateagainst the production database on every deploy that adds migrations