Skip to content

Cloudflare Pages V2 Dev Deploy Runbook

Status: deployed and verified on Cloudflare Pages

Source Of Truth

Manifest:

txt
deploy/cloudflare/pages.frontend.json

Deploy script:

txt
scripts/deploy/cloudflare-pages.mjs

The deployment method is Cloudflare Pages Direct Upload with Wrangler:

bash
npx wrangler pages deploy <DIRECTORY> --project-name <PROJECT_NAME> --branch v2-dev

Official references:

  • Cloudflare Pages Direct Upload: https://developers.cloudflare.com/pages/get-started/direct-upload/
  • Cloudflare Pages custom domains: https://developers.cloudflare.com/pages/configuration/custom-domains/
  • Cloudflare Pages REST API: https://developers.cloudflare.com/pages/configuration/api/
  • Cloudflare Pages monorepos: https://developers.cloudflare.com/pages/configuration/monorepos/

This runbook uses Direct Upload because the v2-dev target has seven Pages surfaces: six frontend apps plus the VitePress docs site. Cloudflare's Git-connected monorepo flow currently documents a default limit of five Pages projects per repository. If v2-dev later moves from Direct Upload to Git integration, request a limit increase, split repositories, or move one surface to another static deployment target before wiring all seven projects to the same repository.

Domain Map

AppPages projectDomain
Adminhoctapaz-v2-dev-admin-webv2.dev.admin.hoctapaz.com
Staffhoctapaz-v2-dev-staff-webv2.dev.staff.hoctapaz.com
Teacherhoctapaz-v2-dev-teacher-webv2.dev.teacher.hoctapaz.com
Studenthoctapaz-v2-dev-student-webv2.dev.student.hoctapaz.com
Parenthoctapaz-v2-dev-parent-webv2.dev.parent.hoctapaz.com
Publichoctapaz-v2-dev-public-webv2.dev.hoctapaz.com
Docshoctapaz-v2-dev-docs-webv2.dev.docs.hoctapaz.com

Provisioned Cloudflare State

As of 2026-07-05, Cloudflare account 9dcb06f92077d2d922d47c332b54cd32 owns the active hoctapaz.com zone 1d768be3b6af3f0a6e52acce15fef09b.

The seven Pages projects have been created with production branch v2-dev:

Pages projectPages subdomain
hoctapaz-v2-dev-admin-webhoctapaz-v2-dev-admin-web.pages.dev
hoctapaz-v2-dev-staff-webhoctapaz-v2-dev-staff-web.pages.dev
hoctapaz-v2-dev-teacher-webhoctapaz-v2-dev-teacher-web.pages.dev
hoctapaz-v2-dev-student-webhoctapaz-v2-dev-student-web.pages.dev
hoctapaz-v2-dev-parent-webhoctapaz-v2-dev-parent-web.pages.dev
hoctapaz-v2-dev-public-webhoctapaz-v2-dev-public-web.pages.dev
hoctapaz-v2-dev-docs-webhoctapaz-v2-dev-docs-web.pages.dev

Each target hostname is attached to its Pages project as a custom domain and has a proxied CNAME in the hoctapaz.com zone:

txt
v2.dev.admin.hoctapaz.com   -> hoctapaz-v2-dev-admin-web.pages.dev
v2.dev.staff.hoctapaz.com   -> hoctapaz-v2-dev-staff-web.pages.dev
v2.dev.teacher.hoctapaz.com -> hoctapaz-v2-dev-teacher-web.pages.dev
v2.dev.student.hoctapaz.com -> hoctapaz-v2-dev-student-web.pages.dev
v2.dev.parent.hoctapaz.com  -> hoctapaz-v2-dev-parent-web.pages.dev
v2.dev.hoctapaz.com         -> hoctapaz-v2-dev-public-web.pages.dev
v2.dev.docs.hoctapaz.com    -> hoctapaz-v2-dev-docs-web.pages.dev

dig @1.1.1.1 resolves all seven names to Cloudflare edge IPs. Cloudflare API reports all seven custom domains as active.

Initial verified deployment evidence:

AppDeployment IDPreview URLCustom domain status
Adminbccd99d5-49a9-4fab-85ff-0954bfa92d71https://bccd99d5.hoctapaz-v2-dev-admin-web.pages.devactive
Staff333f56d2-4a94-488b-8e80-c442840c091ahttps://333f56d2.hoctapaz-v2-dev-staff-web.pages.devactive
Teachere800a534-8ffb-440d-bfbf-b1ea5570e6b9https://e800a534.hoctapaz-v2-dev-teacher-web.pages.devactive
Student10955c91-7270-49f9-bcdd-ab46f8b0cf98https://10955c91.hoctapaz-v2-dev-student-web.pages.devactive
Parentc8d70b0f-1d6d-4547-8d92-a44212303e9ehttps://c8d70b0f.hoctapaz-v2-dev-parent-web.pages.devactive
Public32ad82e9-f8c6-4ab4-ac9a-065674a2b05ehttps://32ad82e9.hoctapaz-v2-dev-public-web.pages.devactive
Docsc54b85c8-6d70-4f84-943f-7281842b4f7ehttps://c54b85c8.hoctapaz-v2-dev-docs-web.pages.devactive

Prerequisites

Wrangler must be authenticated by one of:

bash
npx wrangler login

or non-interactive environment variables:

bash
export CLOUDFLARE_API_TOKEN=...
export CLOUDFLARE_ACCOUNT_ID=...
export VITE_API_BASE_URL=https://<gateway-host>

Token permissions must include Cloudflare Pages edit access. Custom domains require the hoctapaz.com zone to be available in the same Cloudflare account or a valid CNAME/custom-domain setup. The deploy script compiles apps with VITE_APP_ENV=v2-dev; VITE_API_BASE_URL is required so deployed bundles never fall back to localhost or demo auth behavior.

turbo.json whitelists VITE_API_BASE_URL and VITE_APP_ENV for the build task. If you prebuild with Turbo and then deploy with --skip-build, use --force when changing these env values:

bash
VITE_API_BASE_URL=https://hoctapaz.com VITE_APP_ENV=v2-dev pnpm turbo run build '--filter=./apps/*' --force

Commands

Deploy all apps:

bash
cd go-platform
pnpm deploy:cloudflare:pages

Deploy one app:

bash
pnpm deploy:cloudflare:pages -- --app public-web

Deploy only the VitePress docs site:

bash
pnpm docs:build
pnpm deploy:cloudflare:pages -- --app docs-web --skip-build

Create Pages projects before deploying when they do not exist. The v2-dev projects listed above already exist, so this flag should not be used for the current account unless a project was deleted:

bash
pnpm deploy:cloudflare:pages -- --create-projects

Use existing build outputs:

bash
pnpm deploy:cloudflare:pages -- --skip-build

Dry-run command expansion:

bash
pnpm deploy:cloudflare:pages -- --dry-run --skip-build

Custom Domains

After the first successful deployment, attach each domain through Pages Custom domains. Cloudflare docs require associating the hostname with the Pages project; adding a DNS CNAME alone is not sufficient.

If the zone is managed by the same Cloudflare account, the dashboard can create the DNS records during custom-domain setup. Otherwise create the CNAME to the project *.pages.dev hostname after the Pages custom-domain association is created.

Verification

For each domain:

bash
curl -I https://v2.dev.hoctapaz.com/
curl -I https://v2.dev.admin.hoctapaz.com/
curl -I https://v2.dev.staff.hoctapaz.com/
curl -I https://v2.dev.teacher.hoctapaz.com/
curl -I https://v2.dev.student.hoctapaz.com/
curl -I https://v2.dev.parent.hoctapaz.com/
curl -I https://v2.dev.docs.hoctapaz.com/

Expected:

  • 200 for /.
  • SPA fallback works for /login, /register, and /auth/login.
  • Static assets return long cache headers from _headers.

2026-07-05 verification:

  • npx wrangler whoami authenticated against account 9dcb06f92077d2d922d47c332b54cd32.
  • pnpm deploy:cloudflare:pages -- --skip-build uploaded all six app outputs.
  • pnpm deploy:cloudflare:pages -- --app docs-web --skip-build uploaded the VitePress docs output from docs/.vitepress/dist.
  • Cloudflare API reported each latest deployment stage as success.
  • Cloudflare API reported each attached custom domain as active.
  • curl returned 200 text/html for all six frontend custom domains and representative /login//register SPA fallback paths.
  • curl returned 200 text/html for https://v2.dev.docs.hoctapaz.com/, /api/, and /contracts/openapi/.
  • Live Playwright smoke passed for https://v2.dev.hoctapaz.com/ public auth hub and https://v2.dev.admin.hoctapaz.com/ admin login redirect.
  • Live Playwright smoke passed for https://v2.dev.docs.hoctapaz.com/ home, API guide, and OpenAPI contracts pages.

Notes

The Cloudflare API connector can manage projects, custom domains, DNS, and deployment metadata. Local asset upload still uses Wrangler because Pages Direct Upload sends build files from dist/ through Wrangler's upload-token and asset upload flow.

Go-platform documentation is generated from repository Markdown.