CIPatch

Stop paying for superseded GitHub Actions runs

Push three commits to a pull request in ten minutes and you start three full runs. The first two are already obsolete, but you paid for them.

Why it happens

By default every workflow run is independent. A newer commit does not cancel the run for the older one, so a busy pull request bills for each intermediate state — and reviewers only ever look at the last one.

The change

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}

Add it at the top level of the workflow, next to on: and jobs:. Two things matter here:

That expression is the difference between a safe change and a destructive one. A blanket cancel-in-progress: true also cancels pushes, which is fine for tests and wrong for anything that publishes or deploys.

How much it saves

It depends on how often you push to open pull requests. If a quarter of your pull-request runs are superseded before finishing, you stop paying for a quarter of them. Cancelled runs bill only for the minutes they actually consumed, so the saving is real even though the run was started.

When not to do this

CIPatch abstains from all three cases, so it will not propose this in a release pipeline.

Check your own repository in about a minute.

CIPatch checks which of your workflows run on pull requests and whether a safe concurrency block is missing. The scan is read-only, needs no account for the first repository, and changes nothing.

Scan a public repository · Cost calculator