---
title: Parallel Checks
description: Accelerates the merging process by testing the compatibility of multiple queued pull requests in parallel.
---

import { Image } from "astro:assets"
import specChecksListScreenshot from "../../images/merge-queue/parallel-checks/spec-checks-list.png"

Parallel Checks let Mergify test multiple queued pull requests together so you
ship faster. Mergify creates temporary draft PRs that represent cumulative
merges (PR#1), (PR#1+PR#2), (PR#1+PR#2+PR#3), runs CI on them in parallel, then
merges the original PRs once checks pass.

:::tip
  Learn how speculative checks work conceptually at the
  [Merge Queue Academy](https://merge-queue.academy/features/speculative-merging/).
:::

## How Parallel Checks Work

Mergify groups PRs by their position in the queue and the `max_parallel_checks`
value. It creates draft PRs that speculatively combine changes and runs your CI
on each in parallel. For example, with PR #1–#5 and `max_parallel_checks: 3`,
Mergify creates:

- Draft #1: PR #1
- Draft #2: PR #1 + PR #2
- Draft #3: PR #1 + PR #2 + PR #3

```dot class="graph"
strict digraph "Parallel Checks" {
  rankdir=LR;
  fontname="sans-serif";
  fontsize=10;
  nodesep=0.4;
  ranksep=0.6;

  // Default styles
  node [shape=box, style="rounded,filled", fillcolor="#6B7280", fontcolor=white, fontname="sans-serif", margin="0.2,0.1"]
  edge [color="#374151", arrowsize=0.6, penwidth=1.2, fontname="sans-serif"];

  subgraph cluster_mergequeue {
    label = "Merge Queue";
    style="rounded,filled";
    fillcolor="#1CB893";
    color="#000000";
    fontcolor="#000000";
    fontsize=10;

    subgraph cluster_specmerge {
      label="Currently tested (in parallel)";
      // Add a bit of padding around labels inside draft nodes
      node [];
      style="rounded";
      color="#000";
      fontcolor="#000";
      pr1 [label="PR #1", fillcolor="#347D39"]
      pr2 [label="PR #2", fillcolor="#347D39"]
      pr3 [label="PR #3", fillcolor="#347D39"]
      pr1 -> pr2;
      pr2 -> pr3;
    }

    pr4 [label="PR #4", fillcolor="#347D39"]
    pr5 [label="PR #5", fillcolor="#347D39"]
    pr3 -> pr4;
    pr4 -> pr5;
  }

  subgraph cluster_specchecks {
    label = "Currently Tested\n(in Parallel)";
    labelloc="t";
    labeljust="c";
    style="rounded,filled";
    fillcolor="#374151";
    color="#1CB893";
    fontcolor="black";
    fontsize=11;

    traincar1 [label="Draft #1\nPR #1", fontcolor=black, fillcolor="grey"]
    traincar2 [label="Draft #2\nPR #1 + #2", fontcolor=black, fillcolor="grey"]
    traincar3 [label="Draft #3\nPR #1 + #2 + #3", fontcolor=black, fillcolor="grey"]
  }

  // Map queue to drafts
  pr1 -> traincar1 [color="#374151"];
  pr2 -> traincar2 [color="#374151"];
  pr3 -> traincar3 [color="#374151"];

  // CI
  ci [label="Continuous\nIntegration", shape=box, style="rounded,filled", fillcolor="#111827", fontcolor=white]
  traincar1 -> ci [style=dashed, color="#9CA3AF"];
  traincar2 -> ci [style=dashed, color="#9CA3AF"];
  traincar3 -> ci [style=dashed, color="#9CA3AF"];

  { rank=same; traincar1; traincar2; traincar3; }
}

```

This validates the combined outcome ahead of time against your `queue_rules`.
If a draft fails, Mergify removes the culprit PR from the queue and continues
with the rest.

<Image src={specChecksListScreenshot} alt="Mergify parallel checks" />

The result: fewer head-of-line stalls, faster merges, and earlier detection of
incompatibilities.

:::note
  Mergify merges the original PRs, not the temporary drafts. If you prefer
  merging the draft PRs instead, see [Merging the Draft
  PRs](/merge-queue/batches#merging-the-draft-prs).
:::

## Configuring Parallel Checks

Set `merge_queue.max_parallel_checks` to control how many speculative checks run at once:

```yaml
merge_queue:
  max_parallel_checks: 3
```
This example runs up to 3 speculative checks simultaneously. Tune this number
to match your CI capacity and typical PR size/complexity.

## When Things Change

Parallel Checks adapt automatically as your code and rules evolve:

- Failed checks: Mergify removes the failing PR and continues with the rest.

- PR or rule changes: affected PRs are re-evaluated and re-embarked in order.

- Base branch updates: checks restart on the new base; configurable via
  `reset_on_external_merge` — see [Lifecycle: Base Branch
  Updates](/merge-queue/lifecycle#base-branch-updates).

## Skip Intermediate Results (Anti-Flake Protection)

Flaky tests are a reality in most CI pipelines. A test that passes 99% of the
time will still cause intermittent failures that block your merge queue.
`skip_intermediate_results` provides automatic protection against these
transient failures.

### The Problem

You have 3 PRs in the merge queue. PR #1's CI fails due to a flaky test:

```text
Draft #1 (PR #1):           ❌ Failed (flaky test)
Draft #2 (PR #1 + PR #2):   ✅ Passed
Draft #3 (PR #1 + #2 + #3): ✅ Passed
```

**Without `skip_intermediate_results`**: PR #1 gets dequeued. The developer
investigates, finds nothing wrong, reruns CI, waits again. Time wasted.

**With `skip_intermediate_results: true`**: Mergify sees that Draft #2
(which contains PR #1's code) passed. This proves PR #1's failure was
flaky, not a real bug. All 3 PRs merge automatically.

### How It Works

When enabled, Mergify doesn't require every intermediate draft to pass.
Instead, it looks for **any** passing draft that contains the PR's changes:

1. Draft #1 fails (contains PR #1)

2. Draft #2 passes (contains PR #1 + PR #2)

3. Since Draft #2 passed and includes PR #1's code, the failure in Draft #1
   is treated as transient

4. Both PR #1 and PR #2 merge

This is safe because if PR #1 had a **real** bug, Draft #2 would also fail
(it contains the same buggy code). Only flaky failures—where the code is
fine but the test is unreliable—get bypassed.

### Configuration

Enable it in your merge queue configuration:

```yaml
merge_queue:
  skip_intermediate_results: true
```

### When to Use It

**Enable when:**
- Your CI has some flakiness (most pipelines do)
- You have long-running CI where latency matters
- You want to maximize merge throughput
- You're using parallel checks

**Consider disabling when:**
- You need every intermediate state validated for compliance
- You're debugging CI issues and want to see all failures

## Important Considerations

### In‑place checks (no drafts)

Mergify runs checks directly on the original pull request (instead of using
temporary draft PRs) only when of the following are true:

- `queue_rules[*].batch_size = 1`

- `merge_queue.max_parallel_checks = 1`

- No two‑step CI is configured (i.e., no separate `merge_conditions` beyond
  `queue_conditions` in your queue rules)

- Optionally, set `update_bot_account` to avoid in‑place updates blocked 
  by GitHub for security reasons (e.g., PRs from forks that modify workflows, 
  or PRs opened by other bots)

Example configuration enabling in‑place checks:

```yaml
merge_queue:
  max_parallel_checks: 1

queue_rules:
  - name: default
    batch_size: 1
    # use a single set of checks (no two‑step split between queue vs merge)
    queue_conditions:
      - check-success = ci
    update_bot_account: my-org-bot
```

### Branch Protection Settings

Parallel checks operate by creating temporary pull requests, which merge
multiple PRs with the base branch. This process requires the branch protection
setting `Require branches to be up to date before merging` to be disabled.

This does not mean that Mergify will test outdated PRs, but it will merge the
original pull requests once its parallel checks is finished. The original PR
won't be up-to-date according to GitHub, which means using this setting would
block the merge.

### Tuning parallel checks

Adjust `max_parallel_checks` to balance throughput and CI usage. Higher values
increase concurrency; choose a value your CI can handle reliably. For deeper
guidance and trade‑offs (including batching), see [Merge queue
performance](/merge-queue/performance).
