Monorepo CI with Buildkite
Use the Mergify CI Buildkite plugin to run only the pipelines impacted by a pull request.
Mergify’s Buildkite integration makes scopes actionable in your CI. This guide shows how to wire scopes into your pipelines so that each pull request runs only the jobs it truly needs.
Prerequisites
Section titled PrerequisitesBefore you start, make sure you have:
-
jqinstalled on your Buildkite agents (used by the dynamic pipeline script to parse scope results) -
Scopes declared in your
.mergify.ymlso the plugin knows which areas of the repo map to each scope name:
scopes: source: files: frontend: include: - apps/web/**/* api: include: - services/api/**/* docs: include: - docs/**/*Pipeline outline
Section titled Pipeline outlineA typical Buildkite pipeline with scopes consists of two parts:
-
Detect scopes using the
mergifyio/mergify-ciplugin. -
Use a dynamic pipeline to conditionally upload only the steps that match the affected scopes.
Example pipeline
Section titled Example pipelineStatic pipeline entry point
Section titled Static pipeline entry pointsteps: - label: ":mag: Detect scopes" key: detect-scopes plugins: - mergifyio/mergify-ci#v1: action: scopes token: "${MERGIFY_CI_TOKEN}"
- label: ":pipeline: Upload conditional steps" depends_on: detect-scopes command: .buildkite/dynamic-pipeline.sh | buildkite-agent pipeline uploadDynamic pipeline script
Section titled Dynamic pipeline script#!/bin/bashset -euo pipefail
SCOPES=$(buildkite-agent meta-data get "mergify-ci.scopes")
echo "steps:"
if echo "$SCOPES" | jq -e '.frontend == "true"' > /dev/null 2>&1; then cat <<'YAML' - label: ":react: Frontend tests" command: npm test plugins: - mergifyio/mergify-ci#v1: action: junit-process report_path: "junit.xml" token: "${MERGIFY_CI_TOKEN}"YAMLfi
if echo "$SCOPES" | jq -e '.api == "true"' > /dev/null 2>&1; then cat <<'YAML' - label: ":gear: API tests" command: pytest tests/api/ plugins: - mergifyio/mergify-ci#v1: action: junit-process report_path: "reports/*.xml" token: "${MERGIFY_CI_TOKEN}"YAMLfi
if echo "$SCOPES" | jq -e '.docs == "true"' > /dev/null 2>&1; then cat <<'YAML' - label: ":books: Docs build" command: make docsYAMLfiMake the script executable:
chmod +x .buildkite/dynamic-pipeline.shHow it works
Section titled How it works-
The
detect-scopesstep calls the Mergify CI plugin with thescopesaction, which inspects the pull request diff and stores a JSON map of scopes ("true"or"false") as Buildkite meta-data under the keymergify-ci.scopes. -
The dynamic pipeline script reads the scopes meta-data and only emits the steps for scopes that are
"true", so unaffected jobs are skipped entirely. -
Each test step can optionally use the
junit-processaction to upload test results to CI Insights.
Alternative: trigger pipelines
Section titled Alternative: trigger pipelinesIf your monorepo jobs live in separate Buildkite pipelines, you can use
buildkite-agent pipeline upload with trigger steps instead:
#!/bin/bashset -euo pipefail
SCOPES=$(buildkite-agent meta-data get "mergify-ci.scopes")
echo "steps:"
if echo "$SCOPES" | jq -e '.frontend == "true"' > /dev/null 2>&1; then cat <<'YAML' - trigger: "frontend-pipeline" label: ":react: Trigger frontend pipeline" build: branch: "${BUILDKITE_BRANCH}" commit: "${BUILDKITE_COMMIT}"YAMLfi
if echo "$SCOPES" | jq -e '.api == "true"' > /dev/null 2>&1; then cat <<'YAML' - trigger: "api-pipeline" label: ":gear: Trigger API pipeline" build: branch: "${BUILDKITE_BRANCH}" commit: "${BUILDKITE_COMMIT}"YAMLfiMerge Queue integration
Section titled Merge Queue integrationTo reuse the same scopes for merge queue batching, see Merge Queue Scopes.
Was this page helpful?
Thanks for your feedback!