Skip to content
Optimal Lab

DevOps · interactive

Build caching in CI

A monorepo has five packages. Rebuilding and testing all of them on every commit is slow. A build tool that knows the dependency graph only rebuilds what a change can affect, and restores everything else from a cache.

  • utilsno internal depsskipped
  • uidepends on utilsbuild 60s
  • apidepends on utilsskipped
  • webdepends on ui, utilsbuild 120s
  • docsno internal depsskipped

CI time: 3m 0s (everything: 5m 30s)

Changing ui affects ui, web, because they import it. The rest are skipped.

You changed

CI runs

Step 2 of 4

  1. 1

    Know the graph

    Build tools read which packages import which, so they know what a change can break.

    Turborepo, Nx, Bazel, Pants.

  2. 2

    Rebuild the affected set

    The changed package plus everything that depends on it, directly or indirectly.

    turbo run test --filter=...[origin/main]

  3. 3

    Cache outputs by input hash

    Hash a task's inputs; if anyone has built it before, download the outputs instead of rebuilding.

    Shared across CI runs and laptops.

  4. 4

    Cache dependencies too

    Key the package cache on the lockfile hash; parallelise independent jobs.

    key: deps-${{ hashFiles('pnpm-lock.yaml') }}

In production

Tools and technologies

Monorepo tools skip work that a change can't affect.

Not tied to one language — use these names when you search docs or design a system.