Skip to content
Latchkey

How to Use Job-Level Concurrency to Control CI

Without concurrency control, every push spins up a fresh run while stale ones keep burning minutes. Concurrency groups cut the waste.

GitHub Actions concurrency groups cap how many runs of a workflow execute at once for a given key. The two big uses are canceling superseded PR runs and serializing deploys so they never overlap.

1. Cancel superseded PR runs

Group by ref and cancel in-progress runs so only the latest commit on a branch is tested.

.github/workflows/ci.yml
concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true

2. Serialize deploys, do not cancel them

For deploys, queue instead of cancel so an in-flight deploy finishes before the next starts.

.github/workflows/deploy.yml
concurrency:
  group: deploy-production
  cancel-in-progress: false

3. Choose the group key deliberately

The group key defines the scope. Per-ref cancels within a branch; a fixed key serializes everything globally. Pick the narrowest scope that prevents the conflict you care about.

4. Concurrency saves minutes, right-sizing saves dollars

Cancelling stale runs stops wasted minutes; running the surviving job on a cheaper, right-sized Latchkey runner cuts the per-minute cost too. The two stack.

Key takeaways

  • cancel-in-progress: true kills superseded PR runs to save minutes.
  • cancel-in-progress: false serializes deploys so they never overlap.
  • The group key sets the scope; pick the narrowest that prevents the conflict.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →