KEY TAKEAWAYS
- With the default single pending slot, a newer request replaces the waiting one. cancel-in-progress: false protects running work from this cancellation policy, not pending work.[1][2]
- The captured documentation describes queue: max for up to 100 pending jobs or runs. It rejects max combined with cancel-in-progress: true; check support on your platform before adopting it.[1][2]
- Coordinate writers to one deployment target with a shared group in the repository. A workflow/ref-specific key can separate writers that actually need to wait for each other.[1][2]
- A canceled workflow is not a provider rollback receipt. Reconcile the existing deployment operation before authorizing a retry.[3]
First decide whether the waiting request is disposable
A new commit can make an older pending CI check unnecessary. A new release request does not necessarily make an earlier approved release unnecessary. Before giving an agent deployment authority, decide which of those situations applies. GitHub Actions concurrency controls which participating jobs or runs may run and wait together; its default pending slot is not a retain-every-release queue.[1][2]
- Name the target and every writer that can change it, including release workflows, manual paths and other repositories.
- Define supersession explicitly: may a newer artifact replace an unstarted request, or must each distinct release intent retain a disposition?
- Decide separately whether interrupting already-running work is authorized. Do not infer permission to stop a deployment from permission to discard a stale CI check.
These are design decisions, not additional GitHub settings. The guide below follows the option-specific definitions in the captured how-to and workflow syntax. Their generic concurrency-group prose also describes running cancellation too broadly; the explicit cancel-in-progress rule and matching examples are the operative reading used here. This wording conflict was not resolved by a runtime test.[1][2]
Choose the group boundary before the queue policy
GitHub documents at most one running job or workflow in a concurrency group within the repository. Every participating writer must resolve to the intended common group. A name that is unique to a workflow or ref is useful when that work should be independent, but can defeat coordination when multiple workflows or refs deploy to the same target. Group names are case-insensitive: prod and Prod are the same group.[1][2]
| Proposed key | What shares the group | Use or risk |
|---|---|---|
| production-deploy | Participating jobs or workflows in one repository using this same key. | Use for writers to one production target that must wait for each other. Another repository or an external operator is outside this boundary. |
| ${{ github.workflow }}-${{ github.ref }} | The same workflow name and ref combination. | Use for intentionally independent CI. Different workflows or refs get different keys, even if they change one production endpoint. |
| Separate keys for independent targets | Only writers assigned to each target's key. | Use only when those targets really can change independently. Renaming one shared endpoint's group does not create isolation. |
Place concurrency at the top level to gate the whole workflow run, or on the deployment job to gate that participating job. The latter can leave unrelated build work outside the deployment gate. Review every path that can reach the target; sharing an environment label is not a substitute for checking the actual concurrency key and scope.[2]
A repository group is not a cross-repository or provider lock. If a CLI submits an asynchronous deployment and exits, the Actions job ending does not establish that the provider has finished. Broader serialization, duplicate handling and idempotency need their own verified provider or application contract; a group name supplies none of those guarantees. This is operational guidance, not a documented remote-lock feature.[1][2][3]
Choose pending retention and running cancellation separately
queue: single is the documented default: at most one request can be pending, and a newly queued same-group request cancels and replaces an existing pending one. Setting cancel-in-progress: false does not change that rule. Setting it to true also cancels currently running same-group work.[1][2]
| Reader requirement | Policy to consider | What it does not preserve |
|---|---|---|
| Only the newest CI snapshot matters; interruption is authorized. | queue: single; cancel-in-progress: true | Older pending work is replaced and running work is canceled. This is not permission to undo or repeat deployment effects. |
| Finish the current deployment, then use only the newest waiting snapshot. | queue: single; cancel-in-progress: false | The pending request can still be lost to a newer arrival. Choose this only when that supersession is intentional. |
| Distinct pending release intents must wait rather than replace each other. | queue: max; cancel-in-progress: false, after confirming platform support | The documented limit is 100 pending jobs or runs. Extra arrivals when full are canceled; retention is not successful or exactly-once deployment. |
| Keep every intent and cancel running work with the same max policy. | Reject queue: max with cancel-in-progress: true | The captured syntax says this combination produces a workflow validation error. It is not a retain-all-and-interrupt mode. |
| Preserve requests beyond the bound or coordinate external writers. | Evaluate an application/provider queue and shared coordination contract. | Actions concurrency alone does not establish durable intake, cross-repository locking or remote outcome tracking. |
The current captured github.com documentation renders queue: max, but this guide did not verify its rollout for a particular plan, account or GitHub Enterprise Server version. Check the syntax supported by your actual platform before adopting it. If it is unavailable, do not silently substitute single when preserving distinct pending requests is a requirement.[1][2]
The ordering rule is also narrower than dispatch FIFO. GitHub describes first-in-first-out processing according to when each job or run started waiting on the group, not when its workflow was dispatched. Different start times mean dispatch order is not guaranteed. This does not promise commit order or the order in which a remote provider completes asynchronous operations.[1][2]
Completed hypothetical: A is running, B is waiting, C arrives
This example is fictional and unexecuted. One repository has one production target; every deployment job uses production-deploy. A is already running, B has started waiting, and C arrives after B. Running cancellation is disabled, the multi-pending queue has room, and B and C are distinct approved release intents rather than interchangeable snapshots.
| Policy | When C joins the group | Completed maintainer decision |
|---|---|---|
| single + false | A is not canceled by this setting. Pending B is canceled and replaced; C waits. | Reject for these distinct release intents: false protected A, not B. For a different latest-snapshot requirement, record B as intentionally superseded instead. |
| max + false | A continues; B and C remain pending. B began waiting first. | Select the documented bounded policy, subject to platform support. Expect B before C by group-wait order under these inputs; track both intents through actual completion. |
| max + true | The documented configuration is invalid. | Reject before execution. Do not treat it as an alternative that retains B and C while stopping A. |
The completed choice is max with running cancellation disabled, because B must not be superseded by C. Record A as running, B and C as retained pending intents, and their remote outcomes as not yet known. Monitor the pending bound and record any canceled arrival. This is a configuration decision with explicit expected states, not a claim that any deployment succeeded.
Do not reuse this baseline unchanged for single + true: B's arrival would already initiate A's cancellation. A separate hypothetical can have A still shutting down and B still pending when C arrives; C can then replace pending B. The exact shutdown and next-start instant are not established here. Running cancellation is a request handled through the cancellation mechanism, not proof that an already-submitted remote deployment stopped.[1][2][3]
A cancellation decision is not a remote outcome
GitHub's cancellation reference describes server and runner behavior. The server reevaluates running-job conditions; a true condition such as if: always() can let a job continue. For jobs to cancel it sends cancellation messages, and the runner signals steps marked for cancellation, escalating to termination if they do not exit. The server also has a timeout for jobs and steps marked for cancellation. Do not use the workflow label alone to infer that every job or cleanup step stopped.[3]
None of that is a provider-specific rollback receipt. A deployment service may already have accepted work before the caller is interrupted. Whether that operation continues, stops or can be safely repeated depends on that service's contract and the actual operation state. Read both the Actions state and the deployment evidence before deciding what to do next; a currently active old version alone may not rule out queued or in-flight work.[3]
Reconcile a canceled deploy before retrying
The following is proposed deployment-operations guidance, not a GitHub-mandated provider API procedure. Use only reads and recovery actions already authorized for the target. A canceled workflow does not itself authorize another deployment.
- 1. Preserve identity before taking another action: repository, workflow run/job and attempt, target, artifact or commit, and any provider operation ID or acceptance receipt. Keep the canceled run linked to its original release intent.
- 2. Read the existing Actions jobs and steps, then the provider operation using its correlated identity. Distinguish no evidence of acceptance from authoritative evidence of no effect; those are not the same finding.
- 3. Classify the remote disposition: accepted and unfinished, completed with a known result, final no-effect with no late work possible under the contract, or unknown. Check relevant queued/in-flight work as well as the active target state.
- 4. If accepted and unfinished, observe or resume tracking that same operation rather than submitting a new one. If completed, reconcile its result with the intended artifact and current target before choosing any further release or rollback.
- 5. Retry only with current deployment authority and either a verified final no-effect/no-late-work basis or an applicable, verified duplicate-handling contract. Preserve the operation identity as that contract requires; the existence of an idempotency-key field alone is not proof of safe repetition.
- 6. If the result remains unknown, hold resubmission and record the next permitted provider status read, its owner and the evidence needed to decide. Do not turn uncertainty into a new operation ID.
| Scenario input | Fictional finding | Decision now |
|---|---|---|
| A submitted OP-A for artifact release-a to production before cancellation. | An authorized status read correlates OP-A to that target/artifact and reports accepted, completion pending. | Keep OP-A as the original operation and continue its existing status lookup. Do not resubmit A because Actions reports canceled. |
| B and C are still intended later releases. | OP-A's final outcome and the provider's remaining in-flight work are unresolved. | Do not treat Actions gate release as remote completion. Hold any conflicting submission until the provider coordination contract or a reconciled final outcome permits it. |
The recovery answer is deliberately not a fictional success: A's remote result remains unresolved, but the next action is complete and specific—track OP-A, do not duplicate it, and reconcile before another conflicting submission. Queue retention preserves a waiting intent only within its documented boundary; the deployment record must still connect that intent to its final outcome.
What a finished deployment policy must answer
- Which writers share a target, and do they resolve to one group within the repository? Name external writers that this group cannot coordinate.
- May a newer pending request supersede an older one? If not, confirm multi-pending support, account for the finite bound, and track every arrival's disposition.
- Is running cancellation authorized, and is the selected queue/cancellation combination valid? Do not equate false with preservation of pending requests.
- What evidence distinguishes provider acceptance, completion, final no-effect and an unknown result? Who performs the next permitted read when a deployment is canceled?
The useful completion criterion is a retained disposition for each intended release and a correlated remote result—not merely a green or canceled workflow. In the A/B/C example, that means explaining why B must survive C, choosing the bounded policy that can retain both, and refusing to confuse A's cancellation with proof that its provider operation ended.
Evidence limits: this guide uses three official GitHub Docs pages inspected on 15 October 2026 KST. The concurrency how-to and syntax share source material, so they are not independent runtime confirmation. The inspected github/docs source snapshot is b02077198226cf298e574613071a654c46dfa7b7; it pins source passages, not the deployed documentation's complete revision. Page publication/update dates and account rollout remain unverified. No workflows or remote deployments were executed.[1][2][3]
Sources & scope
A documentation-based decision guide for maintainers delegating deployment automation. GitHub Docs was inspected on 15 October 2026 KST; no workflow, deployment or cancellation experiment was run. Examples are fictional and unexecuted. Plan/account rollout and exact GitHub Enterprise Server support for the multi-pending option were not verified. Prepared-edition dates are not evidence of deployment or publication.
- GitHub Docs — Control workflow concurrency ↗
Inspected 15 October 2026 KST. Option-specific pending, queue and cancellation rules; group scope, case and waiting-order semantics. Page publication/update date unknown; platform rollout not established.
- GitHub Docs — Workflow syntax for GitHub Actions ↗
Inspected 15 October 2026 KST. Workflow/job concurrency sections and queue-option incompatibility. Shares concurrency reusable text with the how-to; not independent runtime evidence. Page publication/update date unknown.
- GitHub Docs — Workflow cancellation reference ↗
Inspected 15 October 2026 KST. Server condition reevaluation and runner termination mechanics, not a remote deployment rollback or idempotency contract. Page publication/update date unknown.
Publication history
- — Prepared documentation-based guide with policy tables, a completed hypothetical A/B/C example and a deployment reconciliation procedure. Examples are unexecuted; no runtime outcome is claimed.
Have a correction or a different perspective? Contact Palanthos.