Was watching our CI queue pile up on a busy PR with many force-pushes. Each force-push triggered a new build, old builds kept running. Wasted runner-minutes everywhere.

Fix:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

Put that at the top of the workflow. When a new run for the same branch starts, the previous in-progress run gets cancelled. Branch here means “per PR” or “per branch.”

For main-branch runs, you probably don’t want cancellation — you want every commit to main to be fully tested. Scope accordingly:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

For a deployment workflow, the pattern I use is slightly different: don’t cancel, just queue. A new deploy waits for the previous to finish:

concurrency:
  group: deploy-${{ github.ref }}
  # no cancel-in-progress; they queue

This prevents concurrent deploys from stepping on each other without killing one in the middle (which might leave things in a weird state).

Saved us ~20% of runner-minutes immediately. One of the cheaper wins I’ve done in CI.