Skip to content

Commit 3e62546

Browse files
authored
perf(ci): disable the Turbopack persistent build cache (3.2x faster builds) (#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.
1 parent 897eebd commit 3e62546

3 files changed

Lines changed: 33 additions & 45 deletions

File tree

.github/workflows/ci-cache-cleanup.yml

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
name: CI Cache Cleanup
22

3-
# test-build.yml keys the Next.js build cache sticky disk per branch, so every PR
4-
# leaves a ~5 GB volume behind. Branches are short-lived; the disks aren't. Only
5-
# the pull_request disks are reclaimed — the push disks belong to main/staging/dev
6-
# and must stay warm.
3+
# DRAINING LEGACY DISKS ONLY. test-build.yml no longer mounts a Next.js build
4+
# cache — the Turbopack persistent cache measured 3.2x SLOWER than no cache, so it
5+
# is off. But every PR open while the per-branch key was live left a 5-12 GB volume
6+
# behind, and nothing else reclaims them. This keeps deleting them as those PRs
7+
# close.
8+
#
9+
# Delete this workflow once the backlog is drained (no PR predating the cache
10+
# removal is still open). It is a no-op for new PRs, which never create a disk.
711

812
on:
913
pull_request:
@@ -22,9 +26,12 @@ jobs:
2226
timeout-minutes: 5
2327

2428
steps:
25-
# Must stay byte-identical to the Mount Next.js build cache key in
26-
# test-build.yml, or this deletes nothing and the disks accumulate.
27-
# Non-blocking: PRs skipped by ci.yml's paths-ignore never made a disk.
29+
# A hard-coded legacy drain key. It no longer mirrors anything — the
30+
# Mount Next.js build cache step it used to match was removed with the
31+
# cache. Do not retarget or delete it while PRs from before that removal
32+
# are still open, or their 5-12 GB disks are never reclaimed.
33+
# Non-blocking: PRs skipped by ci.yml's paths-ignore never made a disk,
34+
# and neither does any PR opened after the removal.
2835
- name: Delete sticky disk
2936
uses: useblacksmith/stickydisk-delete@b41313d28b8647d72114c9ba3c96bb04061562b6 # v1
3037
continue-on-error: true

.github/workflows/test-build.yml

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -263,24 +263,12 @@ jobs:
263263
key: ${{ github.repository }}-turbo-cache-build-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}
264264
path: ./.turbo
265265

266-
# Turbopack's persistent build cache (NEXT_TURBOPACK_BUILD_CACHE below)
267-
# writes ~5 GB into .next/cache — a sticky disk mounts it in ~1s where an
268-
# actions/cache round-trip would eat the warm-build win.
269-
#
270-
# Keyed per branch, not just per event. A sticky disk is one mutable volume
271-
# per key: mounting clones the last committed snapshot, job end commits back
272-
# last-write-wins. An event-only key had every open PR restoring a cache
273-
# built from a different branch — 14.0 min vs 9.3 min for the single-writer
274-
# push disk on the same commit. Branch scoping also keeps us off
275-
# cross-commit restore, which turbopackFileSystemCacheForBuild (beta) does
276-
# not document as supported (vercel/next.js#87283: stale HTML from a cache
277-
# built at another commit). ci-cache-cleanup.yml reclaims the disks.
278-
- name: Mount Next.js build cache
279-
uses: ./.github/actions/cache-mount
280-
with:
281-
provider: ${{ vars.CI_PROVIDER }}
282-
key: ${{ github.repository }}-nextjs-cache-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}-${{ github.head_ref || github.ref_name }}
283-
path: ./apps/sim/.next/cache
266+
# No `.next/cache` mount: the Turbopack persistent build cache is off. A
267+
# controlled A/B on one branch (PR #6078) with a byte-identical module graph
268+
# measured compile at 113s with the cache off, 162s cold with it on, and
269+
# 360s warm — the cache made the same build 3.2x slower, and it grew
270+
# 5.1 GB -> 12 GB across two runs of an unchanged tree, so a disk degrades
271+
# the more it is used. Mounting a disk nothing reads would only cost storage.
284272

285273
# Running out of RAM kills the whole VM and surfaces only as "the runner
286274
# has received a shutdown signal" — no mention of memory, ~12 min in. Warn
@@ -300,13 +288,6 @@ jobs:
300288
- name: Install dependencies
301289
run: bun install --frozen-lockfile --ignore-scripts
302290

303-
# The disk mounts successfully whether or not it carried anything and turbo
304-
# buffers the build log, so cache warmth is otherwise unobservable — #5859
305-
# shipped a cache that carried almost nothing and it took a PR to notice.
306-
# Reported, never gated.
307-
- name: Report Next.js cache size (pre-build)
308-
run: du -sh apps/sim/.next/cache 2>/dev/null || echo 'cold — no cache restored'
309-
310291
- name: Build application
311292
env:
312293
NODE_OPTIONS: '--no-warnings --max-old-space-size=8192'
@@ -318,13 +299,4 @@ jobs:
318299
AWS_REGION: 'us-west-2'
319300
ENCRYPTION_KEY: '7cf672e460e430c1fba707575c2b0e2ad5a99dddf9b7b7e3b5646e630861db1c' # dummy key for CI only
320301
TURBO_CACHE_DIR: .turbo
321-
# Opt into Turbopack's persistent build cache (beta) for this CI check
322-
# build only. #5869's 105s-cold/22s-warm was measured locally and has
323-
# never reproduced in CI (compile has ranged 3.5-17.8 min) — local
324-
# numbers, not a CI target.
325-
NEXT_TURBOPACK_BUILD_CACHE: '1'
326302
run: bunx turbo run build --filter=sim
327-
328-
- name: Report Next.js cache size (post-build)
329-
if: always()
330-
run: du -sh apps/sim/.next/cache 2>/dev/null || echo 'no cache written'

apps/sim/next.config.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,20 @@ const nextConfig: NextConfig = {
154154
experimental: {
155155
turbopackFileSystemCacheForDev: false,
156156
/**
157-
* Turbopack's persistent build cache (beta) — opt-in via env so only the
158-
* CI check build uses it; production image builds stay on the default
159-
* cold-build path until the feature stabilizes.
157+
* Turbopack's persistent build cache (beta) stays off — it is a net loss at
158+
* this app's size. A controlled A/B on a byte-identical module graph (PR
159+
* #6078) measured compile at 113s with it off, 162s cold with it on, and 360s
160+
* warm: the cache made the same build 3.2x slower. It also grew 5.1 GB ->
161+
* 12 GB across two runs of an unchanged tree, so a cache degrades the longer
162+
* it lives. Restoring across commits is separately undocumented-as-supported
163+
* (vercel/next.js#87283 reports stale HTML from a cache built elsewhere).
164+
*
165+
* Pinned explicitly rather than left to the Next default: upstream already
166+
* flips this default to true in canary/preview builds (vercel/next.js#94616),
167+
* so relying on the default would let a version bump silently re-enable a
168+
* config we measured as harmful.
160169
*/
161-
turbopackFileSystemCacheForBuild: process.env.NEXT_TURBOPACK_BUILD_CACHE === '1',
170+
turbopackFileSystemCacheForBuild: false,
162171
preloadEntriesOnStart: false,
163172
/**
164173
* Under Turbopack this is not a no-op: the list feeds

0 commit comments

Comments
 (0)