Testing and CI at scale
Fast monorepo CI combines affected tasks and caching with layered tests, while preserving a trustworthy path for repository-wide validation.
Keep most feedback close to the package
Unit tests and static checks should run where code lives. Contract tests protect package APIs. Application integration and end-to-end tests validate assembled behaviour.
A shared library needs tests for its own contract, while critical consumers provide a smaller compatibility suite. Avoid making every package test depend on a full deployed environment.
Build once and promote outputs
CI should install from the lockfile, calculate affected projects, restore trustworthy cache entries, run checks, and produce immutable artifacts. Deployment should promote those artifacts rather than rebuilding with different inputs.
Record the commit, dependency lock, build tool version, and relevant environment used for every artifact.
A pull request pipeline
Treat flaky tests as production defects
A large repository magnifies flaky tests because many teams encounter them. Quarantine only with an owner, issue, and deadline. Track retry rate and time lost.
Tests should isolate state, control time and randomness, await asynchronous work, and avoid relying on execution order.
Keep a complete validation path
Affected-only CI depends on an accurate graph. Schedule full repository verification and run it for changes to root tooling, lockfiles, generators, or boundary rules.
Optimise the common path while preserving a slower source of truth.
Can you explain “Testing and CI at scale” without reaching for the API reference?
Describe the main trade-off, one failure mode, and the decision you would make in a real project.