Cancel superseded runs with concurrency groups
Add a GitHub Actions `concurrency` group scoped to the ref with `cancel-in-progress: true`, so a new push cancels the now-obsolete run instead of leaving both to occupy runners.
Do this
PR workflows declare a top-level concurrency group keyed on the workflow and ref, with cancel-in-progress: true. When a developer pushes again, the superseded run is cancelled instead of running to completion for a commit no one is waiting on. The group is broad enough (per-workflow-per-ref) that it doesn't serialize unrelated jobs.1
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
# Cancel superseded runs on PRs; let main / release runs finish.
cancel-in-progress: ${{ github.event_name == 'pull_request' }}Avoid this
Each new push leaves the old run going, so obsolete commits keep occupying runners.
# No concurrency block. Every push to a PR starts another full run,
# and the superseded ones keep occupying runners until they finish.Why it matters
Without a concurrency group, rapid pushes to a PR leave several full runs racing, every obsolete one still burning a runner until it ends. Cancelling superseded runs reclaims that compute and frees capacity for runs that matter. Keep the group scoped to the ref, not a global constant, an over-narrow or over-broad group is its own problem (it can serialize or cancel jobs you didn't mean to).
When to use
Use it when
PR- and branch-push workflows where developers commonly push several times in quick succession.
Be careful when
Do not use cancel-in-progress: true on the default branch or release workflows where every commit must complete (each may deploy or publish). Scope cancellation to PRs; let main runs finish.
Verify on your repo
Hand this prompt to your coding agent (Claude Code, Cursor, and the like) to audit and fix this practice in your own repo.
Inspect this repo's .github/workflows for a top-level `concurrency:` block on `pull_request` and `push` workflows. Flag any that have none, or one with `cancel-in-progress: false`, so obsolete runs pile up on rapid pushes. Add a `concurrency` group keyed on `${{ github.workflow }}-${{ github.ref }}` with `cancel-in-progress` scoped to PRs, and make sure the default branch and release workflows still let every run finish (never set `cancel-in-progress: true` on `main`). Confirm the group includes `github.ref` so it does not serialize unrelated PRs into one lane. Show me the diff and open a PR rather than applying it blindly.Prefer to check by hand?
Check PR-triggered workflows for a top-level
concurrency:block:grep -rn 'concurrency' .github/workflows/.Flag
pull_request/pushworkflows with no concurrency group, or one withcancel-in-progress: false.Confirm the group key includes
github.ref(per-ref), not a global constant that would serialize every PR into one lane.
More best practices for GitHub Actions
Where to go next in the CI best-practices catalog.
- Runner & Queue
Cut CI queue time in GitHub Actions
GitHub-hosted runners cap how many jobs your account can run at once (20 on Free, more on paid plans), so past that ceiling jobs queue for a free slot no matter how your workflows are written.
- Trigger Scope
Filter workflows by path in GitHub Actions
Add
pathsorpaths-ignoreto expensive workflows so a docs-only or unrelated change doesn't trigger the full test suite.
FAQ
Where does the concurrency block go, workflow or job level?
Put it at the top level of the workflow so it governs the whole run. Job-level concurrency is for finer control, but for cancelling superseded PR runs the workflow-level group keyed on github.ref is what you want.
Is it safe to cancel in-progress runs on main?
No. On the default branch or a release workflow, every commit typically needs its run to complete, cancelling could skip a deploy or publish. Scope cancel-in-progress: true to PR refs and let main runs finish.
Sources
Last updated 2026-07-06
Stop wasting CI minutes on commits no one is waiting on.
One line to install. Faster runs on day one, and agents that open reviewable PRs to keep your pipeline following practices like this one.