Two pull requests can both be green and still break main the moment they both land. Each one was tested against the main that existed when its CI last ran, not against each other. The GitHub merge queue exists for exactly this failure: it revalidates every pull request against the latest version of the target branch, plus the queued changes ahead of it, before anything merges. This piece explains how the queue works, verified against the GitHub docs, when the extra machinery pays for itself, and what it pointedly does not fix. (If you came for the pull requests waiting on your review, that is a different queue: see building a review inbox on GitHub.)
Green plus green equals broken
The failure is not a textual merge conflict; Git catches those. It is the semantic conflict: one PR renames a helper while another adds a call to the old name, one tightens a validation while another starts sending the newly invalid input. Both pass CI, because both were tested against a main that contained neither. The traditional fix is to update your branch and rerun checks before merging, and on a quiet repository that works fine. On a busy one it becomes a treadmill: by the time your rerun finishes, someone else merged, your result is stale again, and the fastest clicker wins. The docs name this dynamic directly: without a queue, authors must update their branch and wait for status checks to finish before trying to merge.
How the GitHub merge queue works
Per the GitHub docs on merge queues, the flow runs like this. Once a pull request passes its required checks, anyone with write access can add it to the queue. The queue then verifies that the changes pass all required status checks when applied to the latest version of the target branch and to any pull requests already queued ahead. It does this by creating temporary branches with a special prefix, each containing the target branch plus the queued changes in order, so a group of pending pull requests is effectively tested as the future main it would produce. Merges then happen in queue order, and main only ever receives combinations that passed together. Two setup details decide whether any of this functions: the branch protection rule must enable Require merge queue, and your CI has to run on the merge_group event, because without that trigger the queued validation runs no checks at all.
How to turn on the GitHub merge queue
Not every repository can use it. Per GitHub’s merge queue docs, the queue works in any public repository owned by an organization, and in private repositories only when the owning organization is on GitHub Enterprise Cloud, so a private repository on the Team plan cannot turn it on. That gap is one reason teams use a third-party queue, and we compare the options in GitHub merge queue alternatives.
- Add the
merge_groupevent to the workflows that produce your required checks, next topull_requestunderon:. Skip this and the queue waits on checks that never start. - In the repository settings, open the branch protection rule or ruleset for the target branch and enable Require merge queue. The rule cannot use a wildcard (
*) in its branch name pattern. - Pick the merge method the queue uses: merge, rebase, or squash.
- Tune the queue, or leave the defaults until you have data. Build concurrency caps how many
merge_groupruns dispatch at once (1 to 100). The minimum and maximum pull requests to merge, plus a wait time, decide how groups batch. The status check timeout decides how long the queue waits on CI before treating silence as a failure. - On a pull request that passes its checks, choose Merge when ready. Anyone with write access to the repository can queue it.
A GitHub App that queues or dequeues pull requests needs read and write on its Merge queues repository permission, which is separate from the pull request and contents permissions. That is the “read and write access to merge queues” line on the install screen of any tool that manages the queue for you.
Failures, ejection, and jumping the queue
When a queued pull request fails checks, the docs are unambiguous: it is removed from the queue, and the temporary branches are recreated without it so the entries behind it can proceed against a clean base. The ejected author fixes and re-queues; nobody else is blocked. This is the property that makes batching safe, since one bad change cannot poison the merges around it for longer than a rebuild. There is also an escape hatch: you can move a pull request to the top of the queue. Use it the way the docs imply you should, sparingly, because a jump causes a full rebuild of every in-progress entry, which means one impatient hotfix can throw away the CI time of the entire queue behind it. A queue that gets jumped daily is a signal that either CI is too slow or too much is being treated as urgent.
When you actually need one
The docs scope the feature honestly: it is particularly useful on branches where a relatively high number of pull requests merge each day from many different users. Two variables govern the decision. Merge volume, because each merge is a chance to invalidate everyone else’s CI results, and CI duration, because slow pipelines widen the staleness window. Ten merges a day against a five-minute pipeline is annoying but survivable by hand; ten merges against a forty-minute pipeline is four hundred minutes of potential staleness, and the treadmill wins. Below that threshold, a merge queue is process for the sake of process. Above it, the queue converts a coordination problem that scaled with team size into infrastructure, which is exactly what infrastructure is for.
What a merge queue does not fix
A merge queue guarantees the combination compiles and the tests pass. It has no opinion on whether the tests assert anything, whether the design is sound, or whether a human ever read the diff; a rubber-stamped approval rides the queue exactly as smoothly as a careful one. If your main is green but your defect rate is not moving, the bottleneck is the review itself, and the evidence on what reviews actually catch says that depends on humans reading with attention, which no merge automation supplies. Disclosure: this is the layer we work on at Pyor, on the view that the useful job for tooling there is organizing the diff so the human read gets faster, not summarizing it away. Queue for integration, review for correctness; neither covers for the other.
Merge queues and trunk-based flow
Merge queues and trunk-based development solve the same problem at different layers. Trunk-based flow asks for small, frequent merges to a single branch, which is precisely the traffic pattern that makes stale CI results common, so teams that adopt the flow tend to hit the queue-shaped problem sooner. The queue, in turn, removes the biggest tax on high-frequency integration: the manual update-and-wait loop. They compound. Small pull requests keep queue batches cheap to rebuild when something is ejected, and the queue keeps small pull requests flowing without a human traffic controller. If you are heading toward trunk-based work, our piece on code review in trunk-based development covers the review side of that transition; the merge queue is the infrastructure that makes the merging side boring, which is the highest compliment infrastructure can earn.
Frequently asked questions
What problem does a GitHub merge queue solve?
Stale CI results. Two pull requests can each pass checks against an older main and still break it when both merge, because neither was tested against the other. The queue validates every pull request against the latest target branch plus the queued changes ahead of it, so what lands has been tested in the combination that will actually exist.
Do small teams need a merge queue?
Usually not. The queue earns its complexity when a busy branch takes many merges a day from many people, and CI takes long enough that results go stale before merging. A small team with fast CI can simply update branches before merging. Turn the queue on when update, wait, retry becomes a daily tax rather than an occasional chore.
What access do you need to use a GitHub merge queue?
Any user with write access to the repository can add a pull request that passes its required checks to the queue. Turning the queue on is a repository admin task, done in a branch protection rule or ruleset. A GitHub App that adds or removes pull requests needs read and write on its own Merge queues repository permission.
How do you jump the GitHub merge queue?
The merge queue interface lets you move a pull request to the top of the queue. Every in-progress group behind it is rebuilt, so all of that CI time is spent again. Save it for real emergencies, like a hotfix while production is broken.