Reuse, release, and deploy

Control concurrency

Cancel stale preview work and serialize production deployments without discarding the current safe release.

Multiple workflow runs can overlap. Three pushes in a minute means three deploys fighting for the same environment. An older run can finish after a newer one and roll production backward without anyone noticing.

Preview and production need different concurrency policy. Copying one block to both workflows is a common mistake.

Concurrency groups runs and decides whether a new run cancels an in-progress one.

Cancel stale preview work

Preview deploys for pull requests should usually keep only the latest commit:

concurrency:
  group: preview-${{ github.head_ref }}
  cancel-in-progress: true

Push twice on the same branch. The first preview run stops. The second one wins. You save minutes and avoid deploying outdated preview code.

Serialize production carefully

Production should not run two deploys at once, but canceling an active production release is risky:

concurrency:
  group: production-deploy
  cancel-in-progress: false

New pushes queue behind the current deploy instead of killing it mid-flight.

Match the group name to the resource you protect: branch for previews, environment name for production, workflow name for tests if needed.

Observe racing pushes

Trigger three rapid commits on one branch. Watch which preview runs cancel and which production runs queue.

A realistic failure: cancel-in-progress: true on production aborts a deploy after files reached the server but before health checks finished. That leaves a messy half state.

Workflow-level concurrency applies to all jobs unless you override per job. Split preview and production into separate workflow files if their concurrency rules differ.

Document the concurrency group names in your pipeline review. Mystery groups make incident response harder.

Try this on your own project: add concurrency to preview jobs first, then tune production separately.

Lesson completed