For contributors

Deployment

Deploy Prood applications to Vercel with Neon Postgres, Upstash Redis, and per-app configuration.

Prood deploys as separate Vercel projects sharing a single Neon Postgres database. Each app has its own environment variables and build configuration.

Production URL map (Prood)

URLApp
prood.comMarketing (apps/web)
dashboard.prood.comMerchant admin
api.prood.comCommerce API
checkout.prood.comHosted checkout
docs.prood.comDocumentation
admin.prood.comPlatform super-admin
{slug}.prood.appStorefront (wildcard on storefront project)
shop.example.comStore custom domain (per merchant)

Set NEXT_PUBLIC_PLATFORM_DOMAIN=prood.app for storefront subdomain resolution only. Platform services use *.prood.com via each app's BETTER_AUTH_URL and public URL env vars.

Deployment architecture

Drag to pan · Scroll to zoom

Prerequisites

  1. Vercel account with team/project access
  2. Neon Postgres provisioned (Vercel marketplace integration)
  3. Upstash Redis provisioned (Vercel marketplace integration)
  4. Payment provider accounts (Stripe, Easypay, and/or Ifthenpay)
  5. Domain names configured

Step 1 — Database setup

Apply the versioned migrations to the production database (and again on every deploy that adds migrations; already-applied ones are skipped):

zsh
# Set DATABASE_URL to the production Neon connection string
DATABASE_URL="postgresql://..." pnpm db:migrate

This creates the commerce and Better Auth tables, the prood_app role and the row-level-security policies. The role that runs the migrations must be able to create roles (the Neon owner role can) and must be the role the apps connect with, because 0000_app_role grants prood_app to it. Postgres 16 or later is required. If prood_app already exists under another owner, a superuser must first run GRANT prood_app TO <migrating_role> WITH ADMIN OPTION. Only run pnpm db:seed if you want the demo store.

Step 2 — Deploy the API

The API must be deployed first — other apps depend on it.

SettingValue
FrameworkNext.js
Root directoryapps/api
Build commandcd ../.. && pnpm build --filter=api
Node.js version24

Environment variables

zsh
DATABASE_URL=postgresql://...
BETTER_AUTH_SECRET=<openssl rand -base64 32>
AUTH_PROXY_SECRET=<openssl rand -base64 32>
BETTER_AUTH_URL=https://api.prood.com
AUTH_COOKIE_DOMAIN=.prood.com
KV_REST_API_URL=https://...
KV_REST_API_TOKEN=...
NEXT_PUBLIC_DASHBOARD_URL=https://dashboard.prood.com
NEXT_PUBLIC_DOCS_URL=https://docs.prood.com
API_PUBLIC_URL=https://api.prood.com
S3_ENDPOINT=https://<account>.eu.r2.cloudflarestorage.com
S3_BUCKET=prood-public
S3_ACCESS_KEY_ID=...
S3_SECRET_ACCESS_KEY=...
S3_PUBLIC_URL=https://prood-media.rbarona.workers.dev
# Also set S3_PUBLIC_URL on storefront, dashboard, admin and checkout: next/image
# reads it at build time and rejects the host without it.
CHECKOUT_API_SECRET=<shared secret>
INTEGRATION_ENCRYPTION_KEY=<openssl rand -base64 32>
RESEND_API_KEY=re_...
RESEND_FROM_EMAIL="Prood <noreply@prood.com>"
NEXT_PUBLIC_PLATFORM_DOMAIN=prood.app

Step 3 — Deploy the storefront

SettingValue
Root directoryapps/storefront
Build commandcd ../.. && pnpm build --filter=storefront

Environment variables

zsh
DATABASE_URL=postgresql://...
COMMERCE_API_URL=https://api.prood.com/v1
BETTER_AUTH_SECRET=<same as API>
KV_REST_API_URL=<same as API>
KV_REST_API_TOKEN=<same as API>
CHECKOUT_URL=https://checkout.prood.com
CHECKOUT_API_SECRET=<same as API>
RESEND_API_KEY=re_...
RESEND_FROM_EMAIL="Prood <noreply@casalume.example>"
NEXT_PUBLIC_PLATFORM_DOMAIN=prood.app

Custom domains are added per-merchant via the dashboard Domains page.

Step 4 — Deploy the checkout app

SettingValue
Root directoryapps/checkout
Build commandcd ../.. && pnpm build --filter=checkout

Environment variables

zsh
KV_REST_API_URL=https://...
KV_REST_API_TOKEN=...
CHECKOUT_API_SECRET=<same as API>
CHECKOUT_URL=https://checkout.prood.com
COMMERCE_API_URL=https://api.prood.com/v1
STOREFRONT_URL=https://storefront.example.com

Payment credentials aren't environment variables. Each store enters its own under Integrations in the dashboard, and there is no platform fallback.

Configure payment webhooks to: https://checkout.prood.com/api/webhooks/{provider}/{orgId}

Step 5 — Deploy the dashboard

SettingValue
Root directoryapps/dashboard
Build commandcd ../.. && pnpm build --filter=dashboard

Environment variables

zsh
DATABASE_URL=postgresql://...
COMMERCE_API_URL=https://api.prood.com/v1
BETTER_AUTH_SECRET=<same as API>
AUTH_PROXY_SECRET=<same as API>
NEXT_PUBLIC_AUTH_URL=https://api.prood.com
INTEGRATION_ENCRYPTION_KEY=<same as API>
VERCEL_TOKEN=<for domain provisioning>
STOREFRONT_VERCEL_PROJECT_ID=<storefront project ID>
VERCEL_TEAM_ID=<team ID>
NEXT_PUBLIC_PLATFORM_DOMAIN=prood.app

Dashboard auth (sign-in, sign-up, organization ops) is issued by apps/api but proxied through the dashboard at /api/auth/* so session cookies stay on the dashboard origin. This is required on separate *.vercel.app preview URLs; with custom domains, set AUTH_COOKIE_DOMAIN=.prood.com on the API project so cookies are also shared across subdomains.

Step 6 — Deploy the platform admin

SettingValue
Root directoryapps/admin
Build commandcd ../.. && pnpm build --filter=admin

Environment variables

zsh
DATABASE_URL=postgresql://...
BETTER_AUTH_SECRET=<same as API>
AUTH_PROXY_SECRET=<same as API>
BETTER_AUTH_URL=https://api.prood.com
NEXT_PUBLIC_AUTH_URL=https://api.prood.com
NEXT_PUBLIC_ADMIN_URL=https://admin.prood.com

apps/admin is for platform operations only. Keep it on a restricted domain. Access is limited to users with the admin role.

Step 7 — Deploy docs and web

AppRoot directoryNotes
docsapps/docsRuns sync:openapi at build time
webapps/webStatic marketing site
zsh
# Docs
NEXT_PUBLIC_DOCS_URL=https://docs.prood.com

# Web
NEXT_PUBLIC_WEB_URL=https://prood.com
NEXT_PUBLIC_DOCS_URL=https://docs.prood.com
NEXT_PUBLIC_DASHBOARD_URL=https://dashboard.prood.com
NEXT_PUBLIC_API_URL=https://api.prood.com

Shared secrets

These must be identical across projects:

SecretApps
BETTER_AUTH_SECRETAPI, dashboard (SSR session validation), storefront
AUTH_PROXY_SECRETAPI, dashboard, admin
CHECKOUT_API_SECRETAPI, storefront, checkout
INTEGRATION_ENCRYPTION_KEYAPI, dashboard
DATABASE_URLAPI, storefront, dashboard, admin
KV_REST_API_URL, KV_REST_API_TOKENAPI, storefront, checkout

Caching in production

The storefront uses Next.js Cache Components:

  • Catalog pages: 'use cache' with per-tenant tags
  • Cart/checkout/account: dynamic (cookie/session dependent)
  • Cache invalidation: dashboard product updates trigger revalidateTag via API

Production checklist

  • Strong secrets generated for BETTER_AUTH_SECRET, AUTH_PROXY_SECRET, CHECKOUT_API_SECRET, INTEGRATION_ENCRYPTION_KEY
  • NEXT_PUBLIC_PLATFORM_DOMAIN configured
  • Upstash Redis provisioned for checkout and auth rate limits, with KV_REST_API_URL and KV_REST_API_TOKEN set on API, storefront and checkout
  • Payment webhooks pointed to checkout domain
  • Resend sender uses a verified production domain
  • pnpm db:migrate run against production database
  • Custom domains verified for at least one merchant
  • SSL certificates active on all domains