Run it locally

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.com in production and http://localhost:3001 locally, with /dashboard, /admin or /pay on 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.app address in production, http://localhost:3005 locally.

Database

VariableRequiredUsed byDescription
DATABASE_URLYesAll appsNeon Postgres connection string. Shared by commerce data (@prood/platform) and Better Auth tables.
DATABASE_URL="postgresql://user:password@host/db?sslmode=require"

Multi-tenancy

VariableRequiredUsed byDescription
NEXT_PUBLIC_PLATFORM_DOMAINProdStorefront, Dashboard, APIApex for merchant storefront subdomains only ({slug}.prood.app). Platform services run on prood.com. Example: prood.app.

Storage

VariableDefaultDescription
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)

VariableRequiredUsed byDescription
BETTER_AUTH_SECRETYesAPI, dashboard, admin, storefrontSession signing secret. Generate: openssl rand -base64 32
AUTH_PROXY_SECRETProdAPI, dashboard, adminDashboard 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_URLYesAPI, dashboard, adminPublic 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_URLYesDashboard, adminInternal 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_URLYesAPI, dashboard, docs, webThe marketing site and gateway: https://prood.com (locally http://localhost:3001).
NEXT_PUBLIC_DASHBOARD_URLYesAPI, dashboard, docs, webMerchant dashboard URL, with its path: https://prood.com/dashboard (locally http://localhost:3001/dashboard).
NEXT_PUBLIC_ADMIN_URLYesAPI, adminPlatform admin URL, with its path: https://prood.com/admin (locally http://localhost:3001/admin).
NEXT_PUBLIC_API_URLYesDashboard, docs, webPublic origin of the REST API, which the gateway serves: https://prood.com (locally http://localhost:3001).
NEXT_PUBLIC_STOREFRONT_URLYesAPI, dashboard, storefrontStorefront apex, e.g. https://prood.app. Stores are its subdomains, so never a single store's host.
AUTH_COOKIE_DOMAINNoAPILeave 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_IDOptionalAPI, dashboard, adminThe 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_ORIGINSOptionalAPI, dashboard, adminThe 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.

VariableRequiredReceivesLocal default
DASHBOARD_ORIGINOn Vercel/dashboardhttp://localhost:3002
ADMIN_ORIGINOn Vercel/adminhttp://localhost:3006
DOCS_ORIGINOn Vercel/docs, /api/searchhttp://localhost:3003
CHECKOUT_ORIGINOn Vercel/payhttp://localhost:3004
API_ORIGINOn Vercel/v1, /mcp, /api/auth, /.well-known/agent-configurationhttp://localhost:3005

Seed credentials

VariableDescription
ADMIN_EMAILInitial platform admin email (used by pnpm db:seed)
ADMIN_PASSWORDInitial 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

VariableRequiredDescription
CHECKOUT_URLYesPublic 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_SECRETYesShared secret between storefront and checkout. Sent as x-checkout-secret header. Generate: openssl rand -base64 32
COMMERCE_API_URLYesInternal API base, with /v1, for webhook forwarding: the API project's own address in production. Default: http://localhost:3005/v1

Upstash Redis

VariableRequiredUsed byDescription
KV_REST_API_URLCheckout, production authapps/checkout, apps/api, apps/storefrontRedis REST endpoint for checkout sessions and auth rate limits
KV_REST_API_TOKENCheckout, production authapps/checkout, apps/api, apps/storefrontRedis 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:

VariableDescription
VERCEL_TOKENVercel API token
STOREFRONT_VERCEL_PROJECT_IDStorefront Vercel project ID. Do not use Vercel's injected VERCEL_PROJECT_ID; it points at the current project, not necessarily the storefront.
VERCEL_TEAM_IDVercel team ID (if applicable)

Commerce API

VariableDefaultDescription
COMMERCE_API_URLhttp://localhost:3005/v1Internal base URL for @prood/api-client in storefront and dashboard: the API project's own address, with /v1
API_PUBLIC_URLhttp://localhost:3001Public API origin for Agent Auth OpenAPI proxy and discovery: https://prood.com in production
TRUST_PROXYfalseSet true behind a reverse proxy for JWT aud validation

Integration encryption

VariableDescription
INTEGRATION_ENCRYPTION_KEYYes

Marketing site

VariableDescription
NEXT_PUBLIC_DOCS_URLOrigin 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

AppCritical vars
webNEXT_PUBLIC_WEB_URL, NEXT_PUBLIC_DOCS_URL, NEXT_PUBLIC_DASHBOARD_URL, NEXT_PUBLIC_API_URL, and the five *_ORIGIN variables on Vercel
storefrontDATABASE_URL, COMMERCE_API_URL, BETTER_AUTH_SECRET, KV_REST_API_*, CHECKOUT_URL, CHECKOUT_API_SECRET
dashboardDATABASE_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)
checkoutKV_REST_API_*, CHECKOUT_API_SECRET, COMMERCE_API_URL
apiDATABASE_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_*
adminDATABASE_URL, BETTER_AUTH_SECRET, AUTH_PROXY_SECRET, BETTER_AUTH_URL, API_PUBLIC_URL, NEXT_PUBLIC_AUTH_URL, NEXT_PUBLIC_ADMIN_URL, PASSKEY_* (optional)
docsNEXT_PUBLIC_WEB_URL, NEXT_PUBLIC_DOCS_URL, NEXT_PUBLIC_DASHBOARD_URL, NEXT_PUBLIC_API_URL (OpenAPI synced at build time)

Production checklist

  1. Generate strong secrets: BETTER_AUTH_SECRET, AUTH_PROXY_SECRET, CHECKOUT_API_SECRET, INTEGRATION_ENCRYPTION_KEY
  2. Configure NEXT_PUBLIC_PLATFORM_DOMAIN for subdomain tenants Set the one-domain URLs, the gateway's five *_ORIGIN variables on prood-web, and PASSKEY_RP_ID=prood.com with PASSKEY_ORIGINS=https://prood.com. Leave AUTH_COOKIE_DOMAIN unset
  3. Provision Upstash Redis for checkout and auth rate limits, and set KV_REST_API_* on API, storefront and checkout
  4. Set RESEND_API_KEY and a verified-domain RESEND_FROM_EMAIL
  5. Run pnpm db:migrate against the production database on every deploy that adds migrations