---
title: Scopes with Other Build Tools
description: Configure merge queue scopes using your preferred monorepo tooling.
---

If you're using monorepo tools that have built-in
dependency graph analysis, you can use their affected project detection instead of file
patterns. This approach is often more accurate because these tools understand your project's
dependency relationships.

## Configuring Manual Scopes

To use the manual scopes mechanism, configure Mergify to expect scopes from your CI system:

```yaml
scopes:
  source:
    manual:

queue_rules:
  - name: default
    batch_size: 5
```

## Detecting Scopes with Your Build Tool

Use your monorepo tool to determine affected projects and upload them to
Mergify.

### GitHub Actions

```yaml
name: Detect Scopes
on:
  pull_request:

jobs:
  detect-scopes:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v5
        with:
          # The queue-aware base commit must exist locally: monorepo tools
          # resolve the base/head range through git.
          fetch-depth: 0

      - name: Get git refs
        id: refs
        uses: Mergifyio/gha-mergify-ci@@@GHA_MERGIFY_CI_VERSION@@
        with:
          action: scopes-git-refs

      - name: Get scopes
        id: scopes
        env:
          HEAD: ${{ steps.refs.outputs.head }}
          BASE: ${{ steps.refs.outputs.base }}
        run: |
          # scopes-git-refs reports an empty base on any event that is neither
          # a pull request nor a push. Diffing against an empty revision, or
          # letting the build tool fall back to its own default base, reports
          # scopes for the wrong range.
          [ -n "$BASE" ] || { echo "no base ref reported" >&2; exit 1; }

          # A failed command piped into paste still exits 0 and writes an
          # empty scope list, which the queue reads as "this pull request
          # affects nothing", so capture the projects first.
          projects=$(my_monorepo_command_to_get_impacted_projects "$BASE" "$HEAD") || exit 1
          scopes=$(printf '%s\n' "$projects" | paste -sd, -)
          echo "scopes=$scopes" >> "$GITHUB_OUTPUT"

      - name: Scopes upload
        uses: Mergifyio/gha-mergify-ci@@@GHA_MERGIFY_CI_VERSION@@
        with:
          action: scopes-upload
          token: ${{ secrets.MERGIFY_TOKEN }}
          scopes: ${{ steps.scopes.outputs.scopes }}
```

### Buildkite

Using the
[`mergifyio/mergify-ci`](https://github.com/Mergifyio/mergify-ci-buildkite-plugin)
Buildkite plugin, a first step resolves the merge-queue-aware base and head
SHAs and exposes them as meta-data, a second computes the affected projects with
your monorepo tool into the `mergify-ci.scopes` meta-data, and a third uploads them. The
upload runs in its own step because the plugin replaces the step's command, so a
step that both detects and uploads never runs its detection:

```yaml
steps:
  - label: ":mag: Get git refs"
    key: git-refs
    plugins:
      - mergifyio/mergify-ci#@@BUILDKITE_PLUGIN_VERSION@@:
          action: scopes-git-refs

  - label: ":mag: Detect scopes"
    key: detect-scopes
    depends_on: git-refs
    command: |
      # The base meta-data is only published when a base was resolved, so a
      # missing key means there is no base to diff against. Check the value
      # too: an empty one would send the build tool back to its own default
      # base and report scopes for the wrong range.
      BASE=$(buildkite-agent meta-data get "mergify-ci.base") || exit 1
      HEAD=$(buildkite-agent meta-data get "mergify-ci.head") || exit 1
      [ -n "$$BASE" ] || { echo "no base ref reported" >&2; exit 1; }
      # A failed command piped into paste still exits 0 and writes an empty
      # scope list, which the queue reads as "this pull request affects
      # nothing", so capture the projects first.
      PROJECTS=$(my_monorepo_command_to_get_impacted_projects "$$BASE" "$$HEAD") || exit 1
      SCOPES=$(printf '%s\n' "$$PROJECTS" | paste -sd, -)
      buildkite-agent meta-data set "mergify-ci.scopes" "$$SCOPES"

  - label: ":mag: Upload scopes"
    depends_on: detect-scopes
    plugins:
      - mergifyio/mergify-ci#@@BUILDKITE_PLUGIN_VERSION@@:
          action: scopes-upload
```

The plugin reads your [application key](/api/usage) from `MERGIFY_TOKEN` in
the agent's environment. Without it the step still runs, but it logs a warning
and sends nothing, and the build stays green, so a missing token looks like a
pipeline that reports no scopes.

<BuildkiteTokenNote />

### Any CI (Mergify CLI)

<ScopesDetection
  command={String.raw`# A failed command piped into jq still exits 0 and writes a well-formed,
# empty scopes.json, which the queue reads as "this pull request affects
# nothing".
PROJECTS=$(my_monorepo_command_to_get_impacted_projects "$BASE" "$HEAD") || exit 1
printf '%s\n' "$PROJECTS" \
  | jq -R -s '{scopes: split("\n") | map(select(length > 0))}' > scopes.json`}
/>
