Skip to content
← Back to merge queue guide Merge queue feature

Parallel queues

Not every change conflicts with every other change. A CSS tweak in the frontend has nothing to do with a database migration in the backend. Parallel queues (sometimes called partitions or scopes) let those changes merge independently instead of queueing behind each other.

flowchart LR
  subgraph Frontend ["Frontend lane"]
    F1["PR f1"] --> F2["PR f2"]
  end
  subgraph Backend ["Backend lane"]
    B1["PR b1"]
  end
  subgraph Platform ["Platform lane"]
    P1["PR p1"]
  end
  F2 --> Main(("main"))
  B1 --> Main
  P1 --> Main

  style Main fill:#E6F8F2,stroke:#1CB893,color:#1A1D24

Each lane runs its own queue. Independent changes do not block each other on the way to main.

Why a single queue stops scaling

With one shared queue, every PR waits in a single line, including the ones that have nothing to do with each other. With a 20-minute CI pipeline and an 8-hour day, a serial queue caps out at about 24 PRs per day. At 30+ PRs per day, the queue falls behind and your engineers start working around it.

A frontend PR waiting behind a backend migration is a tax with no benefit. The two changes will never conflict.

How parallel queues work

PRs in the same scope are tested against each other in strict order, the way a normal queue works. PRs in different scopes are tested independently and merge in parallel. You define scopes based on your codebase: by directory, by team, or by build target.

A monorepo with three teams might define scopes by directory:

Scope PRs/day Single-queue capacity Status
src/frontend/1224Comfortable
src/backend/1524Comfortable
src/platform/324Nearly empty

Combined throughput is 72 PRs per day, three times the single-queue capacity. Teams merge at their own pace without blocking each other.

Defining scope boundaries

Common approaches:

Approach Works well when Watch out for
By directoryClear folder structure (apps/, libs/)Shared code in /common
By teamStrong code ownershipCross-team changes
By build targetBazel, Nx, Turborepo, PantsRequires build-tool integration
By CI configDifferent test suites per areaConfig drift

Cross-scope changes

The hard part is what happens when a PR touches multiple scopes. The standard approach is the union strategy: the PR joins all affected queues and must pass each one before merging. A change to libs/common used by frontend and backend joins both queues, runs both CI suites, and only merges when both pass.

Some queues let you pick a primary scope or fall back to a global queue for cross-cutting changes. Either works. Pick one and make the rule legible to your developers.

Scope design principles

Good scope boundaries share two characteristics. They have low coupling, meaning changes rarely cross boundaries (if 30% of your PRs touch multiple scopes, your boundaries are too fine). They have clear ownership, meaning developers know which scope a change belongs to without needing to ask.

Start coarse (2 to 3 partitions) and refine over time. Granular scopes create overhead and make cross-scope changes painful. Coarse ones do the job for most teams.

Related features

See how to configure parallel queues (scopes) in Mergify.

Stop blocking unrelated PRs.

Mergify supports scopes natively. Define them by file path or label and watch your monorepo throughput climb without adding CI capacity.