CI deploys: scoped API token, wrangler pinned, migrations before code

Build once, apply D1 migrations, then deploy each environment with --env. wrangler-action on GitHub, npx wrangler on GitLab; the token lives in CI secrets.

Workers

· Chapter

38

·

3

min read

The answer. A deploy from a laptop is a deploy from whatever branch was checked out; that is how a stale branch once reverted two launched integrations on our production Worker. In CI, the Worker is built once, database migrations run next, and only then does each environment deploy, in parallel, with wrangler deploy --env <name>. Authentication is an API token with the "Edit Cloudflare Workers" template scoped to one account (plus D1 or Pages permissions if those are deployed), stored as a CI secret and read by Wrangler from CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID. Pin the Wrangler version so a CI run and a local run agree. Cloudflare's own Workers Builds does the same for GitHub or GitLab repos without a pipeline file, if you do not need custom steps.

The pattern.

# .gitlab-ci.yml (GitHub Actions: cloudflare/wrangler-action@v3 with apiToken + command)
stages: [build, migrate, deploy]
build:   { stage: build,   script: [npm ci, npm run build], artifacts: { paths: [dist/] } }
migrate: { stage: migrate, script: [npx wrangler@4 d1 migrations apply app-db --remote --env production],
           rules: [{ if: '$CI_COMMIT_BRANCH == "main"' }] }
deploy_production:
  stage: deploy
  script: [npx wrangler@4 deploy --env production]
  rules: [{ if: '$CI_COMMIT_BRANCH == "main"' }]
  environment: { name: production }
# CLOUDFLARE_API_TOKEN / CLOUDFLARE_ACCOUNT_ID: masked, protected CI variables

Watch out.

  • Migrate before deploy and keep schema changes backward compatible, or the old code runs against the new schema for the gap between the two jobs.
  • A Pages preview deploy from main needs --branch <preview-branch>; without it the preview lands in production.
  • Rotate the token like a password: scope it to the account, set an expiry, and never reuse the local OAuth login in CI.

Related: deploy-with-rollback-target-health-probe · scoped-api-tokens-minted-from-master-token · pages-production-branch-not-main-alias-url-tell