AppSeed Docs
Deployment & Operations

Releasing to prod

Cut a develop→main release, deploy both Workers, and verify the web version actually activated (not just uploaded).

AppSeed follows Gitflow: feature branches integrate into develop, and a release promotes develop to main. Production deploys off main. A full release is four steps — cut, deploy, verify, and check — and the "verify" step is the one that bites, so don't skip it.

1. Cut the release (develop → main)

Make sure develop is green and every change you intend to ship has merged. Then open and merge a release PR:

gh pr create --base main --head develop --title "Release vX.Y.Z — <summary>" --body "..."
gh pr merge <pr> --merge          # a MERGE commit — never --squash

Merge with --merge, not --squash. A release must keep main and develop sharing history. Squashing a release rewrites the lineage and causes every-file conflicts on the next release. (Feature PRs into develop are squash-merged as usual; only the develop → main release is a merge commit.)

Then tag the merge commit and push the tag — the tag is the version marker (the package.json version stays static):

git checkout main && git pull
git tag -a vX.Y.Z <merge-sha> -m "Release vX.Y.Z — <summary>"
git push origin vX.Y.Z

2. Deploy the Workers

  • Web Worker — the push to main triggers Workers Builds, which builds the OpenNext bundle and uploads a new version.
  • Realtime Worker — deploy it by hand (it is not in the Workers Builds pipeline):
npm run deploy:realtime           # wrangler deploy --env production, in apps/realtime

3. Verify the web version actually activated

A version upload is not a deployment. Workers Builds reliably uploads a new version, but the active deployment does not always advance to it on its own — so confirm the release is genuinely live. The fastest check is to hit a URL that only exists in this release (a new page or route). If it 404s, the new code is not serving yet.

# a release-only page should now resolve; an existing one confirms the site is up
curl -s -o /dev/null -w "%{http_code}\n" https://<your-domain>/docs/<new-page-in-this-release>

If the active deployment did not advance (versions uploaded but the old one is still serving), activate the newest CI-built version manually:

# Authenticate wrangler with YOUR Cloudflare account. EITHER a scoped API token:
export CLOUDFLARE_API_TOKEN="<token with Workers Scripts:Edit on this account>"

# OR a Global API Key — then the token variable MUST be unset (it takes precedence):
# unset CLOUDFLARE_API_TOKEN
# export CLOUDFLARE_API_KEY="<your global api key>"
# export CLOUDFLARE_EMAIL="<your cloudflare account email>"

npx wrangler versions list --name <web-worker-name>          # newest version is last
npx wrangler versions view <version-id> --name <web-worker-name>   # confirm it lists env.ASSETS
npx wrangler versions deploy <version-id>@100 --name <web-worker-name> --yes

Two rules for this step:

  • Activate the CI-built version — do not deploy the web Worker from a local build:cf. In this monorepo, a local OpenNext build hits hoisted-node_modules copy errors and can produce an unsound bundle. The version Workers Builds already uploaded is the trustworthy artifact; just point traffic at it. (main and the release-merge on develop have identical web trees, so the version uploaded right after the push is the correct release bundle.)
  • Confirm assets, not just HTML. Fetch a /_next/static/*.css URL — it must return 200 (text/css). A 404 means an assetless version went live; see the assets-binding gotcha in Secrets & env.

4. Post-release checks

  • Homepage returns 200, and a release-only route returns 200 (step 3).
  • A /_next/static/*.css asset returns 200 (text/css) — the site is styled.
  • The realtime Worker is healthy (its /agents/* and /realtime/* routes respond).

Why the manual activation step exists

On the AppSeed reference deployment, Workers Builds was observed to upload versions on each main push without activating them — leaving prod on a stale build until a manual wrangler versions deploy. Until a given deployment's Workers Builds connection is confirmed to auto-activate at 100%, treat step 3's manual activation as a standard part of every release. See the CI with Workers Builds page for how the pipeline is wired.

On this page