Skip to content

[EXPERIMENT — do not merge] Is the Turbopack FS build cache a net win? - #6078

Closed
waleedlatif1 wants to merge 4 commits into
stagingfrom
exp/turbopack-build-cache-ab
Closed

[EXPERIMENT — do not merge] Is the Turbopack FS build cache a net win?#6078
waleedlatif1 wants to merge 4 commits into
stagingfrom
exp/turbopack-build-cache-ab

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Draft, do not merge. Three measurements, then close. See EXPERIMENT.md.

NEXT_TURBOPACK_BUILD_CACHE=1 was added in #5869 assuming a warm Turbopack cache speeds up next build. Observational data from tonight suggests the ordering is cold < perfect-warm < mismatched-warm — i.e. the cache may be costing wall time.

Those observations each varied commit and cache state. This branch holds the tree constant: every commit touches only .github/** + EXPERIMENT.md, so the Next module graph is byte-identical across all three runs and only cache state changes.

run NEXT_TURBOPACK_BUILD_CACHE disk state
A '1' cold (brand-new per-branch key)
B '1' warm, written by A
C '0' ignored

Two traps this defuses, both of which already produced wrong numbers once:

  1. Turbo replay — a .github-only commit leaves Turbo's task inputs unchanged, so Turbo would replay a cached log and reprint a stale compile time, fabricating the measurement. --force prevents it. Five phantom runs had to be discarded from the observational data for exactly this.
  2. Cancelled-run cache writescancel-in-progress means pushing early cancels a run, and a cancelled run still commits its partial cache. This is why an earlier conclusion ("a brand-new sticky key is not cold") was wrong: the "first" run had a cancelled sibling 3 minutes prior that had already written 5.1 GB. Each run here must reach completed before the next push.

Measurable only because #6072 added the pre/post du reporting.

Do not merge. Adds --force so Turbo cannot replay a cached log and reprint
a stale compile time, which a .github-only commit would otherwise trigger.
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview Jul 30, 2026 1:27am

Request Review

Module graph byte-identical to run A; only the disk state differs.
NEXT_TURBOPACK_BUILD_CACHE '1' -> '0'. Module graph still byte-identical to
runs A and B; the 12G on the sticky disk is now ignored by Turbopack.
Records run B: warm was 2.2x SLOWER than cold and the cache grew 5.1G -> 12G.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

Experiment complete. Result, from three runs on this branch with a byte-identical module graph:

run flag pre-build disk compile Build App job
C — cache OFF 5.1G (ignored) 113s 2m53s
A — cache ON, cold 4.0K 162s 3m54s
B — cache ON, warm 5.1G 360s 8m18s

A warm cache made the identical build 3.2× slower, and the cache grew 5.1 GB → 12 GB across two runs of an unchanged tree — so a disk degrades the longer it lives, which explains the progressive slowdown observed up to 11.7 min.

Acted on in #6080, which disables the cache and removes the mount. Closing — this branch was never for merging (it carries turbo --force, which exists only to stop Turbo replaying a cached log and reprinting a stale compile time).

Two incidental findings, both now fixed separately: a 1 ms real-clock flake in pi-lifetime.test.ts (#6082, merged) and the blocks/registry-maps TDZ import cycle (#6083).

waleedlatif1 added a commit that referenced this pull request Jul 30, 2026
…uilds) (#6080)

* perf(ci): disable the Turbopack persistent build cache

It is a net loss at this app's size. A controlled A/B on one branch (#6078),
three runs with a byte-identical module graph so only cache state varied:

  cache OFF        113s compile, 2m53s job
  cache ON, cold   162s compile, 3m54s job
  cache ON, warm   360s compile, 8m18s job

The cache made the same build 3.2x slower. It also grew 5.1 GB -> 12 GB
across two runs of an unchanged tree, which explains the progressive
degradation seen on longer-lived disks (up to 11.7 min): the more a disk is
written, the more the next run must read and revalidate. Flag manipulation
is visible in the logs — the cache-on runs print
`✓ turbopackFileSystemCacheForBuild`, the cache-off run omits it — and every
run used `turbo --force` so none is a replayed log.

#5869 enabled this on locally-measured numbers (105s cold -> 22s warm) that
never reproduced in CI and are inverted here. #6072 then branch-scoped the
disk to stop PRs restoring each other's caches; that fixed a real problem,
but with the cache off the disk is unnecessary, so the mount, the pre/post
size reporting, and the env gate all go with it.

Pins `turbopackFileSystemCacheForBuild: false` explicitly rather than relying
on the Next default: upstream already flips that default to true in
canary/preview builds (vercel/next.js#94616), so leaning on the default would
let a version bump silently re-enable this.

Keeps ci-cache-cleanup.yml, re-scoped to draining the 5-12 GB volumes that
PRs opened while the per-branch key was live still hold — nothing else
reclaims them. It is a no-op for new PRs and can be deleted once drained.

Caveat: n=1 per cell. The 3.2x effect size and agreement with ~15 prior
observations make it convincing, but this is three runs, not a distribution.

* docs(ci): correct the cleanup key comment after the mount was removed

Greptile P2: the delete step still claimed its key must stay byte-identical
to the Mount Next.js build cache step in test-build.yml, but this PR removes
that mount. It is now a hard-coded legacy drain key that mirrors nothing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant