CICDCost.com is an independent comparison resource. Not affiliated with GitHub, GitLab, CircleCI, Buildkite, or any CI/CD vendor. Try our CI/CD calculator

Monorepo CI cost in 2026: where the minutes go in a unified codebase

Monorepos concentrate engineering work in a single repository where any change can theoretically affect any other code. Without selective test execution, every push runs the entire test suite, which scales the CI bill with codebase size rather than with change volume. The affected-only pattern (Nx, Turborepo, Bazel) brings the bill back to linear in change volume, where it belongs. This page covers the cost shape of monorepo CI in 2026, the tooling that makes it tractable, and the realistic before-and-after numbers from teams that adopted the pattern.

The change-detection problem

A naive monorepo CI runs every test on every push: a one-line PR to fix a typo runs the same 90-minute test suite as a major refactor. With Nx affected-only or Bazel selective testing, the same PR runs only the 12 tests that depend on the changed file. Result: 70-95% reduction in CI minutes per PR, with no loss of safety on the typical small change.

Why monorepo CI cost scales super-linearly

Three compounding effects. First, the test suite grows roughly with codebase size. A 10-service monorepo has roughly 10x the tests of a single-service repo at similar maturity. Second, the PR rate grows roughly with developer count, and developer count tends to scale with codebase size. Third, the required-check set tends to grow with the diversity of services in the repo: each new language, framework, or integration adds checks that must run.

Compounded, a 50-developer monorepo with 15 services and 4 required checks per service generates 50 x 5 (pushes/dev/day) x 20 (working days) x 60 (4 checks x 15 services) checks per month = 300,000 check executions. At 4 minutes average per check that is 1.2 million minutes, $7,200 at $0.006/min Linux. The actual bill is usually a fraction of this because not every check runs against every service, but the worst-case shape is the unconstrained run-everything-on-every-push pattern.

The fix is structural: only run tests for services that are affected by the change. The dependency graph is the new infrastructure component you maintain.

Affected-only with Nx

Nx is the dominant tool for JavaScript and TypeScript monorepos. The model: you define a project structure (apps and libs), and Nx infers the dependency graph from imports. nx affected --target=test runs tests only for projects affected by the changes in the working tree (or, in CI, between two git refs).

Implementation effort: moderate. Existing JS monorepos can usually adopt Nx incrementally over 2-4 weeks. The dependency graph builds from imports automatically; the developer-facing change is wrapping common commands (test, build, lint) with the nx CLI. CI integration: replace npm test with nx affected --target=test --base=$BASE_SHA --head=$HEAD_SHA.

Realistic savings: 60-85% reduction in test minutes per PR for a typical mature monorepo. The variance comes from change profile: PRs that touch shared libraries trigger many affected projects, so the savings on those PRs are smaller. PRs that touch one specific service trigger a small affected set with large savings.

Affected-only with Turborepo

Turborepo is the lighter-weight alternative to Nx for JS/TS monorepos. The conceptual model is similar: define tasks per package, Turborepo computes the affected set from changes. The big draw is the simpler config and the integration with Vercel's remote cache product.

Implementation effort: lower than Nx for greenfield setups. Existing repos with established build tooling (Webpack, Vite, custom build scripts) sometimes need significant adaptation to fit the Turborepo task model. CI integration: turbo run test --filter=...$BASE_SHA.

Realistic savings: similar to Nx at 60-85% per PR. The remote cache (Vercel-hosted at $25-100/seat/month, or self-hosted at the cost of an S3 bucket) adds another layer: any task previously executed with the same inputs returns from cache rather than re-running.

Bazel for the largest monorepos

For very large monorepos (250k+ lines, 50+ services, multi-language) Bazel is the canonical choice. Bazel's hermetic build model and content-addressed cache are designed precisely for the "run only what changed" problem at the largest scale. Google, Pinterest, Airbnb, and many similar engineering organisations run Bazel for this reason.

The migration cost is significant. Existing repos typically need 6-12 months of engineering time to fully adopt Bazel because every BUILD file must be authored explicitly and every dependency must be declared. The payoff is order-of-magnitude reduction in CI minutes for very large codebases, plus the operational benefits of hermetic builds (reproducibility, distributed caching, cross-language consistency).

Bazel is not the right answer for smaller monorepos: the migration cost exceeds the saving. The threshold where Bazel pays back is roughly the 250k-line, 50-service mark, where the lifetime CI savings exceed the multi-month migration. Below that, Nx or Turborepo deliver most of the benefit with much less migration cost.

Worked example: 50-dev JS monorepo

A 50-developer JS monorepo with 15 services. Without affected-only: every PR runs all 15 service test suites at average 6 min each = 90 min per push. 50 devs x 5 pushes/day x 20 days x 90 min = 450,000 min/month. At GitHub Actions Linux $0.006: $2,700/month, plus the rounding tax (each of those 90-min jobs is one job, so rounding is small for individual jobs but the total is right).

With Nx affected-only: average PR touches 2-3 services. New per-PR cost: 3 services x 6 min = 18 min. New monthly: 50 x 5 x 20 x 18 = 90,000 min/month, $540 at GitHub Actions Linux. Saving: $2,160/month, or roughly 80% reduction. The Nx adoption project takes about a month for a team familiar with the tool, so payback is roughly 2-3 weeks of CI cost.

Add the Nx Cloud distributed cache on top: another 30-50% reduction because tasks previously executed with the same inputs return from cache. New monthly cost: $300-450. Total saving from no-tooling baseline: 85-90%.

The dependency-graph maintenance cost

Affected-only is not free of operational cost. The dependency graph must be maintained: when a developer adds a new shared dependency between two services, the graph must update or the affected-only logic will miss it. With Nx and Turborepo this is automatic if developers use standard imports; with Bazel it is explicit in BUILD files.

The failure mode of dependency graph drift is silent: a test gets skipped that should have run, a regression escapes to production. The mitigation is a nightly "run everything" build that catches what affected-only missed during the day. The nightly run is more expensive per execution than a single PR but runs only once a day, so the total monthly cost is small.

Frequently Asked Questions

Why does monorepo CI cost more than multi-repo?

Without affected-only test selection, a monorepo runs the entire test suite on every push regardless of what changed. A multi-repo setup only runs the test suite of the repo that changed. So a one-line change to a tiny utility runs the same 90-minute test suite as a major refactor of the platform. Monorepo CI cost scales with codebase size; multi-repo CI cost scales with change volume. Affected-only selection brings monorepo back to scaling with change volume, where it belongs.

What is affected-only test selection?

Affected-only test selection runs only the tests that depend on changed files. Tools build a dependency graph of the codebase: which files import which, which tests cover which production files. A change to file X triggers only the tests that transitively depend on X. Tools: Nx (JS/TS monorepos), Turborepo, Bazel (multi-language), Pants (multi-language). Realistic savings: 70-95% of test minutes on a typical monorepo PR.

Is Bazel worth it for CI cost?

Yes for codebases above ~250k lines or above ~20 services. Bazel's hermetic build model and remote cache deliver near-perfect cache reuse: any file or test that has been built or run before with the same inputs returns from cache instantly. The setup cost is significant: typically 6-12 months of engineering time to migrate a non-Bazel repo. The ongoing operational cost is lower than the alternatives once you are past the migration. Below the size thresholds, Nx or Turborepo deliver most of the benefit with much less migration cost.

What is the typical CI bill for a monorepo?

Highly variable. A 50-developer JavaScript monorepo with 15 services and no affected-only selection typically pays $3,000-8,000/month in CI. The same team with Turborepo and remote caching typically pays $800-2,000. The same team again with Nx Cloud and full distributed caching often lands at $400-1,200. The 5-10x range between worst and best is achievable with available tools; the gap is closed by engineering investment, not by switching CI vendors.

Should every team use a monorepo?

No. Monorepos work well for tightly-coupled product teams shipping a single application or platform. They work poorly for autonomous teams that want independent release cadences and tooling choices. The CI cost story is not a primary reason to choose either model: with affected-only selection, monorepo CI is competitive with multi-repo. With unrestricted full-suite runs, monorepo CI is dramatically more expensive.

Updated 2026-05-11