---
title: Keep Merge Queue Pull Requests Out of Your Way
description: Why the merge queue opens draft pull requests, when it checks in place instead, and how to filter queue pull requests out of searches, notifications, webhooks and CI.
---

To test what it is about to merge, the merge queue often opens a temporary
draft pull request on a branch of its own: a queue pull request, called a batch
PR on other pages. Queue pull requests show up in your
pull request list, in webhooks, in deploy previews and in any tool that reacts
to new pull requests. This page explains when and why the queue opens them, how
to configure a queue that does without, and how to filter them out everywhere
else.

## Why the Queue Opens Draft Pull Requests

The queue has to run your CI on the exact code it is about to merge. Often that
code is not any single pull request's branch:

- **Batches.** With [`batch_size`](/merge-queue/batches) above 1, the queue
  tests several pull requests together, so it builds a branch holding all of
  them on top of the base branch.

- **Parallel checks.** With
  [`max_parallel_checks`](/merge-queue/performance#parallel-checks) above 1,
  the queue tests the next pull requests speculatively, on top of the ones
  still being checked ahead of them. Each of those predicted states needs its
  own branch.

- **Bisection.** When a batch fails, the queue
  [splits it](/merge-queue/batches#handling-batch-failure-or-timeout) to find
  the culprit, and each half is tested on a new branch.

- **Retries.** With
  [`max_checks_retries`](/merge-queue/lifecycle#automatic-ci-retries) above 0,
  every retry recreates the draft to get a fresh CI run.

- **Two-step CI.** With [`merge_conditions`](/merge-queue/two-step) that differ
  from `queue_conditions`, the merge conditions are evaluated on the draft, so
  the heavier suite runs there and not on the original pull request.

- **Parallel and isolated modes.** In
  [`parallel` and `isolated` modes](/merge-queue/queue-modes), the queue tests
  several groups of pull requests side by side, each on its own branch.

The draft pull request is how your CI learns about that branch and how its
results come back to the queue. Mergify deletes the branch, and with it the
draft, once the batch is done.

## When the Queue Checks in Place

When none of the above applies, the queue skips the draft. It updates the
original pull request with the latest base branch, runs CI on the pull request
itself, and merges it. A queue rule checks in place only when **all** of these
hold:

- `merge_conditions` is empty, or lists the same conditions as
  `queue_conditions` (no two-step CI).

- `batch_size` is 1. With a `{min, max}` range, `max` is 1.

- `max_checks_retries` is 0.

- `merge_queue.max_parallel_checks` is 1.

- `merge_queue.mode` is `serial`.

`batch_size`, `max_checks_retries` and `mode` default to those values, but
`max_parallel_checks` defaults to 5. A queue that has never touched it opens
draft pull requests, so the smallest configuration that checks in place sets it
explicitly:

```yaml
merge_queue:
  max_parallel_checks: 1

queue_rules:
  - name: default
    queue_conditions:
      - check-success = ci
```

The conditions are the same list as in [In-place checks (no batch
PRs)](/merge-queue/batches#in-place-checks-no-batch-prs), which also covers
`update_bot_account` and pull requests coming from forks.

Checking in place gives up what the drafts were buying. The queue tests one pull
request at a time, so it merges at most one pull request per CI run, and every
queued pull request gets an update from the base branch pushed to it. See [The
Trade-offs](/merge-queue/performance#the-trade-offs-reliability-cost-and-velocity-rcv-theorem)
to weigh that against your merge rate. If you need batches or parallel checks,
keep the drafts and filter them with the recipes below.

## Recognize a Queue Pull Request

A queue pull request carries four markers:

- **Head branch:** the
  [`queue_branch_prefix`](/configuration/file-format/#queue-rules) followed by
  10 hexadecimal characters, for example `mergify/merge-queue/a76b1f3d25`.

- **Author:** `mergify[bot]`, written `app/mergify` in GitHub search, unless the
  queue rule sets [`draft_bot_account`](/configuration/file-format/#queue-rules).

- **State:** draft.

- **Title:** starts with `merge queue: `.

Match on the head branch. It holds for every queue pull request, whoever opens
it and whatever state it is in, while the others have exceptions: a queue rule
with `draft_bot_account` opens drafts under that user's name, the
[`merge-batch`](/merge-queue/merge-strategies#merge-batch) method marks the
draft ready for review before merging it, and a draft state also matches the
drafts your own developers open.

The prefix defaults to `mergify/merge-queue/` and is set per queue rule. If you
change it, change your filters to match. See [How Leftover Branches Are
Matched](/merge-queue/lifecycle#how-leftover-branches-are-matched) for the exact
shape of the name.

:::caution
  Your CI still has to run on queue pull requests. The queue merges only once
  the checks in `merge_conditions` pass on the draft, so a filter that skips a
  required check leaves the batch waiting until it times out. Filter only what
  does not gate the merge, such as notifications and previews, and keep every
  required check running.
:::

## Filter Recipes

### GitHub Search

Add `-author:app/mergify` to a pull request search to hide queue pull requests:

```text
is:pr is:open -author:app/mergify
```

If a queue rule sets `draft_bot_account`, filter on the branch instead.
`head:` matches branch names starting with the value:

```text
is:pr is:open -head:mergify/merge-queue/
```

Save the search as a bookmark, or paste it into the filter box of the pull
request list.

### Webhooks and Slack

A service that receives GitHub's `pull_request` webhook can drop queue pull
requests by testing the head branch in the payload. In Python:

```python
QUEUE_BRANCH_PREFIX = "mergify/merge-queue/"

def is_queue_pull_request(payload: dict) -> bool:
    return payload["pull_request"]["head"]["ref"].startswith(QUEUE_BRANCH_PREFIX)
```

The same test fits any automation that posts to Slack or another chat tool,
whether a workflow or a bot of your own. To also drop the
drafts your developers open, test `payload["pull_request"]["draft"]` as well,
but keep the branch test: a draft check alone misses the queue pull request
once `merge-batch` marks it ready.

The GitHub app for Slack filters pull requests by label only, so it cannot
exclude queue pull requests by branch or author. Route those notifications
through a filter of your own if they are too noisy.

### GitHub Actions

Skip a job on queue pull requests with an `if:` condition on the head branch.
This suits jobs that do not gate the merge, such as deploy previews or
labelers:

```yaml
on:
  pull_request:

jobs:
  preview:
    if: ${{ !startsWith(github.head_ref, 'mergify/merge-queue/') }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: make deploy-preview
```

The queue also pushes its branch, so a workflow triggered on `push` runs for it
too. On `push`, filter with `branches-ignore`, which matches the pushed branch:

```yaml
on:
  push:
    branches-ignore:
      - "mergify/merge-queue/**"
```

:::note
  On `pull_request`, `branches` and `branches-ignore` match the **base** branch,
  not the head branch, so they cannot exclude queue pull requests. Use a
  job-level `if:` as above.
:::

To do the opposite and run a job only in the queue, see [Two-Step
CI](/merge-queue/two-step#github-actions).

### CircleCI

CircleCI builds the queue branch when it is pushed. Ignore it in a workflow's
branch filter:

```yaml
workflows:
  preview:
    jobs:
      - deploy-preview:
          filters:
            branches:
              ignore: /^mergify\/merge-queue\/.*/
```

### Buildkite

Skip a step on queue branches with a conditional:

```yaml
steps:
  - label: ":rocket: Deploy preview"
    command: make deploy-preview
    if: build.branch !~ /^mergify\/merge-queue\//
```

A step-level `branches: "!mergify/merge-queue/*"` filter does the same. The
pipeline-wide branch filter in the pipeline settings skips every step,
including the ones your `merge_conditions` require, so keep it for pipelines
that never gate a merge.

### Jenkins

In a multibranch pipeline, the queue branch can be built both as a branch and
as a pull request, where `BRANCH_NAME` becomes `PR-123`. Cover both with a
`when` block:

```groovy
stage('Deploy preview') {
  when {
    not {
      anyOf {
        branch 'mergify/merge-queue/*'
        changeRequest branch: 'mergify/merge-queue/*', comparator: 'GLOB'
      }
    }
  }
  steps {
    sh 'make deploy-preview'
  }
}
```

### Vercel

Turn off Vercel deployments for queue branches in `vercel.json` with
`git.deploymentEnabled`:

```json
{
  "git": {
    "deploymentEnabled": {
      "mergify/merge-queue/*": false
    }
  }
}
```

Vercel then skips the preview deployment for every queue branch. With a custom
`queue_branch_prefix`, use that prefix followed by `*`.
