Scopes with Turborepo
Configure merge queue scopes using Turborepo's dependency graph awareness.
If you’re using monorepo tools like Turborepo 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
Section titled Configuring Manual ScopesTo use the manual scopes mechanism, configure Mergify to expect scopes from your CI system:
scopes: source: manual:
queue_rules: - name: default batch_size: 5Detecting Scopes with Turborepo
Section titled Detecting Scopes with TurborepoUse the turbo run build --dry=json command to determine affected projects
and upload them to Mergify.
GitHub Actions
Section titled GitHub Actionsname: Detect Scopeson: pull_request:
jobs: detect-scopes: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v5 with: # The queue-aware base commit must exist locally: turbo resolves # the base/head range through git. fetch-depth: 0
- name: Get git refs id: refs uses: Mergifyio/gha-mergify-ci@v25 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 turbo piped into jq still exits 0 and writes an empty # scope list, which the queue reads as "this pull request affects # nothing", so capture the dry run first. dry=$(npx turbo run build --dry=json --filter="[$BASE...$HEAD]") || exit 1 scopes=$(printf '%s' "$dry" | jq -r '.packages | join(",")') echo "scopes=$scopes" >> "$GITHUB_OUTPUT"
- name: Scopes upload uses: Mergifyio/gha-mergify-ci@v25 with: action: scopes-upload token: ${{ secrets.MERGIFY_TOKEN }} scopes: ${{ steps.scopes.outputs.scopes }}Buildkite
Section titled BuildkiteUsing the
mergifyio/mergify-ci
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
turbo run build --dry=json 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:
steps: - label: ":mag: Get git refs" key: git-refs plugins: - mergifyio/mergify-ci#v7: 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 turbo piped into jq still exits 0 and writes an empty scope # list, which the queue reads as "this pull request affects nothing", # so capture the dry run first. DRY=$(npx turbo run build --dry=json --filter="[$$BASE...$$HEAD]") || exit 1 SCOPES=$(printf '%s' "$$DRY" | jq -r '.packages | join(",")') buildkite-agent meta-data set "mergify-ci.scopes" "$$SCOPES"
- label: ":mag: Upload scopes" depends_on: detect-scopes plugins: - mergifyio/mergify-ci#v7: action: scopes-uploadThe plugin reads your application key 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.
Any CI (Mergify CLI)
Section titled Any CI (Mergify CLI)
Install the Mergify CLI in your pipeline and export
MERGIFY_TOKEN. Use
mergify ci git-refs to get the
merge-queue-aware base and head SHAs and
mergify ci scopes-send to upload the
detected scopes:
REFS=$(mergify ci git-refs --format json)# -e so a null ref fails here instead of flowing on as the literal string# "null": git-refs reports no base outside pull request and push events.BASE=$(printf '%s' "$REFS" | jq -er '.base') || exit 1HEAD=$(printf '%s' "$REFS" | jq -er '.head') || exit 1
# A failed turbo piped into jq still exits 0 and writes a well-formed, empty# scopes.json, which the queue reads as "this pull request affects nothing".DRY=$(npx turbo run build --dry=json --filter="[$BASE...$HEAD]") || exit 1# error() rather than a bare .packages: if turbo ever stops reporting that key,# jq would write {"scopes": null} and exit 0. This block runs in whatever shell# your CI uses, so it cannot lean on set -e.printf '%s' "$DRY" \| jq '{scopes: (.packages // error("turbo reported no packages"))}' > scopes.json || exit 1
mergify ci scopes-send --scopes-json scopes.jsonWas this page helpful?
Thanks for your feedback!