CI with Workers Builds
How the web Worker auto-deploys on push via Cloudflare Workers Builds, and why the realtime Worker deploys manually.
Valcraven uses Cloudflare Workers Builds — Cloudflare's built-in, Git-connected CI/CD — to deploy the web Worker automatically. Once your repository is connected to the Worker, every push to the production branch (main) triggers a build-and-deploy on Cloudflare's infrastructure. There's no GitHub Actions deploy workflow to maintain and no wrangler API token to store as a repo secret for routine deploys.
How it works
Workers Builds is configured in the Cloudflare dashboard, not by a file in this repo — you connect your GitHub (or GitLab) repository to the Worker and set the branch, build command, and deploy command there. For the Valcraven web Worker that means:
- Trigger — a push to
main. - Build — the OpenNext build (
npm run build:cf), which producesapps/web/.open-next. - Deploy —
wrangler deployof that bundle (whatnpm run deploy:cfruns under the hood).
Because the exact commands are configured in the dashboard, treat the above as the shape of the pipeline rather than a checked-in config. The important properties for downstream apps:
- Only the web Worker auto-deploys. Workers Builds is scoped to a single Worker + repo connection.
- Secrets set with
wrangler secret putpersist across deploys — Workers Builds does not re-apply them, and you should never put secret values in the build config. See Secrets & env. - D1 migrations are not run by the build. Apply them separately (see Running migrations in prod) — a deploy that ships code expecting a new column will fail at runtime until the migration is applied to the remote D1.
The realtime Worker deploys manually
The realtime Worker (apps/realtime) is a separate Worker and is not part of the Workers Builds pipeline. Deploy it by hand whenever apps/realtime changes:
npm run deploy:realtime # wrangler deploy --env production, in apps/realtimeOr ship both Workers at once (app first, so the WEB service binding target exists):
npm run deploy:cf:all # build:cf → deploy:cf (web) → deploy:realtimeThis split is intentional: the realtime Worker owns Durable Objects and long-lived WebSocket state, and its production config lives under a named [env.production] env in apps/realtime/wrangler.toml. Keeping it a manual, deliberate deploy avoids surprising the live agent DOs on every push. See Deploying to Cloudflare Workers → The realtime Worker.
The repo's GitHub Actions are on-demand only
Separately from deploys, the repo ships GitHub Actions workflows for verification — ci.yml (lint, typecheck, unit + integration tests, build), e2e.yml (Playwright), and mobile.yml (Expo bundle). All of them are workflow_dispatch only — they do not run automatically on push or pull request. This keeps GitHub Actions cost down during heavy active development. Consequences:
- PRs show no automatic checks. Don't wait for them — verify locally (
npm run build,npm test) instead. - To run a workflow, dispatch it manually from the Actions Run workflow button or the CLI:
gh workflow run ci.yml # optionally: --ref <branch>
gh workflow run e2e.yml
gh workflow run mobile.ymlThese workflows are not the deploy path — they build and test but do not push to Cloudflare. Deploys happen through Workers Builds (web) and deploy:realtime (realtime).