Deploy to Cloudflare Pages
Each store is its own Cloudflare Pages project. The build bakes the brand in
via PUBLIC_* environment variables, so the same commit deploys to every
store by changing only the env.
npm install
PUBLIC_BRAND_SLUG=store-b \PUBLIC_BRAND_NAME='Store B' \PUBLIC_BRAND_LOGO=/images/store-b-logo.png \PUBLIC_BRAND_PRIMARY='#0F766E' \PUBLIC_BRAND_MENU='gear:Gear,apparel:Apparel' \PUBLIC_API_BASE=https://api.store-b.example.com/api/v1 \RCOMMERCE_API_URL=https://api.store-b.example.com \PUBLIC_AIRWALLEX_ENV=demo \PUBLIC_HERO_VIDEO_URL='https://customer-<id>.cloudflarestream.com/<video-id>/iframe?muted=true&preload=true&loop=true&autoplay=true&controls=false' \npm run buildAll PUBLIC_* values are inlined at build time — setting them only in the
Pages dashboard does nothing unless the dashboard’s build environment also
uses them. Simplest reliable setup: keep the full set in a per-brand
wrangler.<brand>.toml (see below) and build with those same values.
Deploy
Section titled “Deploy”npx wrangler pages deploy dist --project-name=<project> --branch=mainAttach the store’s domains to the project (Pages → Settings → Domains), e.g.
store-a.example.com + www.store-a.example.com on my-storefront,
store-b.example.com on store-b-pages.
Per-brand wrangler.toml
Section titled “Per-brand wrangler.toml”storefront/wrangler.store-b.toml is the reference example — copy it per store
and adjust:
# Store B storefront — deploys to the store-b-pages Pages project with# Store B branding and the store-b backend. Build first with the same PUBLIC_*# values inlined (they are baked in at build time):## PUBLIC_BRAND_SLUG=store-b PUBLIC_BRAND_NAME='Store B' \# PUBLIC_BRAND_LOGO=/images/store-b-logo.png PUBLIC_BRAND_PRIMARY=#0F766E \# PUBLIC_BRAND_MENU='gear:Gear,apparel:Apparel' \# PUBLIC_API_BASE=https://api.store-b.example.com/api/v1 \# RCOMMERCE_API_URL=https://api.store-b.example.com \# PUBLIC_AIRWALLEX_ENV=demo \# PUBLIC_HERO_VIDEO_URL='https://…' \# npm run build# npx wrangler pages deploy dist --config wrangler.store-b.toml --branch=mainname = "store-b-pages"pages_build_output_dir = "dist"compatibility_date = "2025-06-01"compatibility_flags = ["nodejs_compat"]
[vars]PUBLIC_AIRWALLEX_ENV = "demo"PUBLIC_API_BASE = "https://api.store-b.example.com/api/v1"RCOMMERCE_API_URL = "https://api.store-b.example.com"PUBLIC_BRAND_SLUG = "store-b"PUBLIC_BRAND_NAME = "Store B"PUBLIC_BRAND_LOGO = "/images/store-b-logo.png"PUBLIC_BRAND_PRIMARY = "#0F766E"PUBLIC_HERO_VIDEO_URL = "https://customer-<id>.cloudflarestream.com/<video-id>/iframe?muted=true&preload=true&loop=true&autoplay=true&controls=false"PUBLIC_BRAND_MENU = "gear:Gear,apparel:Apparel"Two requirements are easy to miss:
compatibility_date = "2025-06-01"— the storefront relies on Pages runtime behavior from this date; do not let the dashboard roll it forward.compatibility_flags = ["nodejs_compat"]— required by the Astro SSR output and the API proxy function.
Pages project environment variables
Section titled “Pages project environment variables”Set these in the project’s production environment (they apply to the runtime proxy, not the build):
| Variable | Example |
|---|---|
RCOMMERCE_API_URL | https://api.store-b.example.com |
PUBLIC_API_BASE | https://api.store-b.example.com/api/v1 |
PUBLIC_AIRWALLEX_ENV | demo or prod |
PUBLIC_BRAND_SLUG | store-b |
PUBLIC_BRAND_NAME | Store B |
PUBLIC_BRAND_LOGO | /images/store-b-logo.png |
PUBLIC_BRAND_PRIMARY | #0F766E |
PUBLIC_BRAND_MENU | gear:Gear,apparel:Apparel |
PUBLIC_HERO_VIDEO_URL | Cloudflare Stream iframe URL |
The Airwallex build-time value is only a fallback: the backend’s checkout
summary (airwallex_env) always takes precedence at runtime.
Rollback
Section titled “Rollback”Pages keeps every deployment; roll back from the dashboard (Deployments → ⋮ → Rollback) or redeploy a previous production deployment.