0005 — Public sites deploy to Cloudflare Pages, one project per tenant
- Status: accepted
- Date: 2026-05-06
- Deciders: Derek
Context
Each tenant has a public-facing static site rendered by Astro. Tenants need their own domain and isolated build pipeline (an Actualize build failure shouldn’t block a different tenant’s site).
Decision
One Cloudflare Pages project per tenant. The build command is the same (pnpm --filter @ark/site build with tenant-specific env vars). The domain is per-tenant. Free tier covers many tenants.
Cloudflare specifically because: actualize-v2 already proves this works, the free tier is genuinely generous, edge-deployed static hosting is what we want, and the CMS rebuild webhook flow (Cloudflare hook URL stored per-org in organizations.deploy_hook_url) is a clean integration point.
Consequences
Easier:
- Per-tenant isolation at the deploy boundary
- Fast static hosting; no cold starts
- Cheap to scale to many tenants
- The CMS-publish-triggers-rebuild flow is already a known-good pattern
Harder:
- Provisioning a new tenant requires a Cloudflare API call (automatable via
wrangler/Cloudflare API in the/new-tenantscript) - Cross-tenant analytics needs a separate provider, not Cloudflare’s per-project analytics
Alternatives considered
- Single Cloudflare Pages project, custom-domain routing per tenant. Loses build isolation; one tenant’s build break breaks deployment for all.
- Vercel. Equivalent feature set; we pick Cloudflare for cost predictability and existing knowledge.
- Self-host static via S3 + CDN. Operationally heavier; gives nothing the managed option doesn’t.