Skip to content

/config/github-actions/concurrency-cancel-in-progress

GitHub Actions concurrency: cancel-in-progress for older runs

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · 1.7.12updated 2026-10-20
tool
GitHub Actions
file
.github/workflows/*.yml
key
concurrency
type
string group, or { group, cancel-in-progress }
default
no limit: every run executes

concurrency puts runs with the same group key in a queue: at most one runs and one waits. With cancel-in-progress: true, a new run cancels the one in progress instead of waiting. Keyed on the workflow and the branch, this stops a pull request from running CI for every intermediate push.

The usual setting

bash
mkdir -p .github/workflows
cat > .github/workflows/ci.yml <<'EOF'
name: CI
on:
  push:
    branches: [main]
  pull_request:

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

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - run: echo "testing ${{ github.sha }}"
EOF
actionlint -no-color .github/workflows/ci.yml && echo "actionlint: no problems"

Output

actionlint: no problems

github.head_ref is the PR branch, so all pushes to one PR share a group. The expression in cancel-in-progress cancels superseded runs on pull requests, but lets every push to main finish.

Keys

KeyMeaning
groupany string or expression; runs with the same value are serialised
cancel-in-progresstrue cancels the running member of the group when a new run arrives; can be an expression
(job level) jobs.<id>.concurrencythe same, for a single job such as a deployment

Deployments

yaml
jobs:
  deploy:
    runs-on: ubuntu-latest
    concurrency:
      group: deploy-production
      cancel-in-progress: false   # never cancel a deployment halfway

Sources