Julien Danjou

Nov 27, 2025

5 min

read

Monorepo CI for GitHub Actions: Run Exactly the Tests You Need, Nothing More

landmark photography of trees near rocky mountain under blue skies daytime
landmark photography of trees near rocky mountain under blue skies daytime

Run only the tests that matter in your monorepo. Mergify Monorepo CI detects which parts of your repo each pull request touches and triggers the right GitHub Actions jobs, then aggregates them into a single CI gate for branch protection or Merge Queue.

Monorepos are incredible for collaboration. One place for all services, shared libraries, infrastructure, frontend apps, and docs. One unified workflow. One shared CI. But there's a catch.

When everything lives in the same repository, CI suddenly becomes expensive. A tiny change in a single service can trigger the entire build matrix, including frontend, backend, SDKs, documentation, integration tests, packaging, and sometimes even deployment workflows.

Most teams respond the same way:

"Eh, let everything run. It's simpler."

But that stops working as your repo grows. So we built something better.

Today, we're announcing Mergify Monorepo CI for GitHub Actions: a straightforward system that detects exactly which parts of your repo a pull request touches, runs only the workflows affected by those changes, and publishes a single CI gate you can use in branch protection or Merge Queue.

No rebuild storm. No redundant test suites. No wasted CI minutes.

Just… the right tests, for the right pull request.

Why Monorepos Hurt CI (Even When You Do Everything "Right")

Imagine this repo layout:


A change in docs/ still triggers:

  • frontend tests

  • backend tests

  • integration tests

  • shared package builds

  • maybe even deployments

Multiply that by dozens of PRs per day, and your CI bill + pipeline duration explode. 🤯

Monorepos work because teams move faster. CI slows you down because it cannot see what's actually relevant.

So we taught it.

The Key Idea: Scopes

A scope is a named slice of your repository.

Example from .mergify.yml:

scopes:
  source:
    files:
      frontend:
        includes:
          - apps/web/**/*
      api:
        includes:
          - services/api/**

In plain English:

  • "frontend scope" = anything inside apps/web/

  • "api scope" = anything inside services/api/

  • "docs scope" = anything in the docs folder

When a pull request modifies files, Mergify instantly computes which scopes changed.

That becomes the input to GitHub Actions.

In a diagram:


Now your CI can say:

  • Run frontend tests → yes

  • Run api tests → no

  • Run docs checks → yes

Nothing else.

The Missing Piece: GitHub Actions Integration

The project we built (gha-mergify-ci) is a tiny but powerful GitHub Action that:

  1. Reads your scopes from a configuration file

  2. Inspects the PR diff

  3. Outputs a JSON map of touched scopes

  4. Lets every job decide whether it should run

Here's the minimal workflow:


You only run jobs that matter. Every other job is simply skipped, safely and predictably.

A Single Gate for Branch Protection

Optionally, you can aggregate everything into one job:


This publishes a single status check you can use in:

✔ GitHub branch protection

✔ GitHub rulesets

✔ Mergify Merge Queue

One green dot. One source of truth.

Monorepo CI + Merge Queue = Your Fast Lane

Then, scopes don't stop at CI. Once you define them, Mergify's Merge Queue automatically uses them to:

  • batch together related PRs

  • avoid CI duplication

  • run speculative tests only where necessary

  • accelerate merges across large repos

Scopes become the shared language between CI, batching, merge workflows, and review automation. This is the missing glue monorepo teams have been trying to build manually with bash scripts and matrix gymnastics.

Why This Matters

Monorepos are powerful, but only if CI scales with them.

With Mergify Monorepo CI, you get:

💸 Lower CI cost: fewer redundant test suites

Faster PR feedback: only relevant jobs run

🧠 Clearer workflows: CI tied to actual code ownership

🛡 Consistent branch protection via a single gate

🚀 Smarter Merge Queue batching powered by scopes

All with a tiny, declarative config file and one GitHub Action. This is the monorepo CI system GitHub Actions was missing.

Recommended blogposts

Nov 27, 2025

5 min

read

Monorepo CI for GitHub Actions: Run Exactly the Tests You Need, Nothing More

Run only the tests that matter in your monorepo. Mergify Monorepo CI detects which parts of your repo each pull request touches and triggers the right GitHub Actions jobs, then aggregates them into a single CI gate for branch protection or Merge Queue.

Julien Danjou

Nov 27, 2025

5 min

read

Monorepo CI for GitHub Actions: Run Exactly the Tests You Need, Nothing More

Run only the tests that matter in your monorepo. Mergify Monorepo CI detects which parts of your repo each pull request touches and triggers the right GitHub Actions jobs, then aggregates them into a single CI gate for branch protection or Merge Queue.

Julien Danjou

Nov 27, 2025

5 min

read

Monorepo CI for GitHub Actions: Run Exactly the Tests You Need, Nothing More

Run only the tests that matter in your monorepo. Mergify Monorepo CI detects which parts of your repo each pull request touches and triggers the right GitHub Actions jobs, then aggregates them into a single CI gate for branch protection or Merge Queue.

Julien Danjou

Nov 27, 2025

5 min

read

Monorepo CI for GitHub Actions: Run Exactly the Tests You Need, Nothing More

Run only the tests that matter in your monorepo. Mergify Monorepo CI detects which parts of your repo each pull request touches and triggers the right GitHub Actions jobs, then aggregates them into a single CI gate for branch protection or Merge Queue.

Julien Danjou

Nov 25, 2025

7 min

read

await Is Not a Context Switch: Understanding Python's Coroutines vs Tasks

Python’s async model is misunderstood, especially by engineers coming from JS or C#. In Python, awaiting a coroutine doesn’t yield to the event loop. Only tasks create concurrency. This post explains why that distinction matters and how it affects locking, design, and correctness.

Mehdi Abaakouk

Nov 25, 2025

7 min

read

await Is Not a Context Switch: Understanding Python's Coroutines vs Tasks

Python’s async model is misunderstood, especially by engineers coming from JS or C#. In Python, awaiting a coroutine doesn’t yield to the event loop. Only tasks create concurrency. This post explains why that distinction matters and how it affects locking, design, and correctness.

Mehdi Abaakouk

Nov 25, 2025

7 min

read

await Is Not a Context Switch: Understanding Python's Coroutines vs Tasks

Python’s async model is misunderstood, especially by engineers coming from JS or C#. In Python, awaiting a coroutine doesn’t yield to the event loop. Only tasks create concurrency. This post explains why that distinction matters and how it affects locking, design, and correctness.

Mehdi Abaakouk

Nov 25, 2025

7 min

read

await Is Not a Context Switch: Understanding Python's Coroutines vs Tasks

Python’s async model is misunderstood, especially by engineers coming from JS or C#. In Python, awaiting a coroutine doesn’t yield to the event loop. Only tasks create concurrency. This post explains why that distinction matters and how it affects locking, design, and correctness.

Mehdi Abaakouk

Nov 19, 2025

4 min

read

Updating Materialized Views (Without Worrying Too Much)

Materialized views are powerful but painful to change. Here’s how we safely version, refresh, and migrate them without locking production or timing out deployments, plus the approach we use to avoid dangerous DROP/CREATE migrations.

Rémy Duthu

Nov 19, 2025

4 min

read

Updating Materialized Views (Without Worrying Too Much)

Materialized views are powerful but painful to change. Here’s how we safely version, refresh, and migrate them without locking production or timing out deployments, plus the approach we use to avoid dangerous DROP/CREATE migrations.

Rémy Duthu

Nov 19, 2025

4 min

read

Updating Materialized Views (Without Worrying Too Much)

Materialized views are powerful but painful to change. Here’s how we safely version, refresh, and migrate them without locking production or timing out deployments, plus the approach we use to avoid dangerous DROP/CREATE migrations.

Rémy Duthu

Nov 19, 2025

4 min

read

Updating Materialized Views (Without Worrying Too Much)

Materialized views are powerful but painful to change. Here’s how we safely version, refresh, and migrate them without locking production or timing out deployments, plus the approach we use to avoid dangerous DROP/CREATE migrations.

Rémy Duthu

Curious where your CI is slowing you down?

Try CI Insights — observability for CI teams.

Curious where your CI is slowing you down?

Try CI Insights — observability for CI teams.

Curious where your CI is slowing you down?

Try CI Insights — observability for CI teams.

Curious where your CI is slowing you down?

Try CI Insights — observability for CI teams.