Add a concurrency block at the workflow level to group runs by branch: concurrency: { group: '${{ github.workflow }}-${{ github.ref }}', cancel-in-progress: true }
For pull request workflows, use the PR number in the group key to prevent runs on different PRs from cancelling each other: group: 'pr-${{ github.event.pull_request.number }}'
For deployment workflows where you want to queue rather than cancel, set cancel-in-progress: false — the new run will wait for the in-progress run to finish before starting
Apply concurrency at the job level (not just workflow level) when only specific jobs should be serialized: add a concurrency block inside the job definition with a more specific group key
Use a conditional expression for cancel-in-progress to allow main branch runs to complete while cancelling PR branch runs: cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
Verify behavior in the Actions UI: a pending run shows a yellow dot with 'Waiting for a pending job in queue'; cancelled runs show as 'Cancelled' in the workflow history
Known gotchas
Setting both cancel-in-progress: true and a queue limit greater than 1 is not supported and causes a workflow validation error — choose one concurrency control approach
Concurrency groups are scoped to the repository; two different workflows with the same group string will block each other, which can cause unexpected serialization across unrelated workflows
cancel-in-progress cancels the currently running job, not just queued ones; if a deployment job is mid-run, cancellation may leave infrastructure in a partially applied state — use false for irreversible operations
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp