open atlas
↑ Back to track
Frontend Architecture FE · 05 · 09

Monorepo: config and pipeline reading

Read real Turborepo and Nx config snippets, predict the task graph and cache behaviour, and pick the highest-leverage fix.

FE Senior ◷ 14 min
Level
FoundationsJuniorMiddleSenior

The pipeline config and the cache key are where monorepo problems are actually diagnosed. Read the config, predict the task graph and what hashes into the cache, then choose the fix a senior engineer would make first.

Goal

Practise the loop you run on every slow or unsafe monorepo pipeline: read the task config, work out the ordering and the cache key, spot the false hit or false miss, and reach for the structural fix before adding hardware.

Snippet 1 — the task graph

// turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": []
    }
  }
}
Quiz

What ordering does this config produce, and what is the difference between the two dependsOn entries?

Snippet 2 — the cache key

// turbo.json — build task inputs
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "inputs": ["src/**/*.ts", "src/**/*.tsx"],
      "outputs": ["dist/**"]
    }
  }
}
Quiz

A change to the shared root tsconfig.json alters compiler output, but every build still cache-hits and ships stale dist. Reading these inputs, what is the bug and the fix?

Snippet 3 — affected detection

# CI: only build/test what this PR could have broken
npx nx affected -t build test --base=origin/main --head=HEAD
Quiz

On a long-lived release branch this command suddenly reports the whole repo as affected for a tiny diff. Most likely cause?

Snippet 4 — module boundaries

// .eslintrc — @nx/enforce-module-boundaries
{
  "depConstraints": [
    { "sourceTag": "type:feature", "onlyDependOnLibsWithTags": ["type:ui", "type:util"] },
    { "sourceTag": "type:ui",      "onlyDependOnLibsWithTags": ["type:util"] },
    { "sourceTag": "type:util",    "onlyDependOnLibsWithTags": ["type:util"] }
  ]
}
Quiz

Which import does this config reject at lint time, and what graph problem does the rejection prevent?

Recap

Every monorepo pipeline problem is read in config and a git range: the caret in dependsOn decides whether upstream packages build first; the inputs glob is the cache key, where a missing tsconfig is a false hit and a volatile path is a false miss; affected scope is a graph walk over a diff, so a wrong —base inflates it to the whole repo; and depConstraints keep low-level libraries from gaining the fan-in that makes every change global. Read the config, fix the key or the boundary, then re-run and confirm the affected set and hit rate behave. Now when you open an unfamiliar turbo.json or nx.json, you know what to look for: the caret, the inputs list, and the base branch — those three lines tell you whether the pipeline is correct.

Something unclear?

Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.

shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.