Skip to content

Replace docker-image-cache.js with BuildKit registry cache#92799

Open
mmastrac wants to merge 2 commits into
canaryfrom
mmastrac/docker-buildx-cache
Open

Replace docker-image-cache.js with BuildKit registry cache#92799
mmastrac wants to merge 2 commits into
canaryfrom
mmastrac/docker-buildx-cache

Conversation

@mmastrac
Copy link
Copy Markdown
Contributor

@mmastrac mmastrac commented Apr 14, 2026

What

Use a buildkit registry (hosted on top of our turborepo cache emulator) rather than forcing docker to get cached using turborepo.

Why

Buildkit is smarter about layers and can do a lot less work if the local runner has some of the images.

Copy link
Copy Markdown
Contributor Author

mmastrac commented Apr 14, 2026

@nextjs-bot
Copy link
Copy Markdown
Contributor

nextjs-bot commented Apr 14, 2026

Stats from current PR

✅ No significant changes detected

📊 All Metrics
📖 Metrics Glossary

Dev Server Metrics:

  • Listen = TCP port starts accepting connections
  • First Request = HTTP server returns successful response
  • Cold = Fresh build (no cache)
  • Warm = With cached build artifacts

Build Metrics:

  • Fresh = Clean build (no .next directory)
  • Cached = With existing .next directory

Change Thresholds:

  • Time: Changes < 50ms AND < 10%, OR < 2% are insignificant
  • Size: Changes < 1KB AND < 1% are insignificant
  • All other changes are flagged to catch regressions

⚡ Dev Server

Metric Canary PR Change Trend
Cold (Listen) 456ms 455ms ▁▅▅▁▁
Cold (Ready in log) 445ms 444ms ▆▁█▇▂
Cold (First Request) 1.145s 1.119s █▇▁▁█
Warm (Listen) 456ms 456ms ██▅▅▅
Warm (Ready in log) 445ms 446ms ▆▃▃▃▃
Warm (First Request) 344ms 346ms █▂▅▄▇
📦 Dev Server (Webpack) (Legacy)

📦 Dev Server (Webpack)

Metric Canary PR Change Trend
Cold (Listen) 455ms 456ms ▅▁▅▁▅
Cold (Ready in log) 442ms 442ms ▃▂▁▃▁
Cold (First Request) 1.975s 1.976s ▆▆▅▆▄
Warm (Listen) 455ms 455ms █▅▅█▁
Warm (Ready in log) 441ms 441ms ▃▁▂▃▁
Warm (First Request) 1.976s 1.983s ▅▄▃▄▄

⚡ Production Builds

Metric Canary PR Change Trend
Fresh Build 3.988s 4.024s ▁▃▄█▃
Cached Build 3.894s 4.010s ▁▁▃█▂
📦 Production Builds (Webpack) (Legacy)

📦 Production Builds (Webpack)

Metric Canary PR Change Trend
Fresh Build 14.706s 14.653s ▄▃▃▃▁
Cached Build 14.706s 14.831s ▃▃▁▃▂
node_modules Size 494 MB 494 MB ▁████
📦 Bundle Sizes

Bundle Sizes

⚡ Turbopack

Client

Main Bundles
Canary PR Change
04gfaeiu1v7qm.js gzip 151 B N/A -
07rxhp_1_g4mu.js gzip 13.1 kB N/A -
07vz_1vlust95.js gzip 65.5 kB N/A -
08avva-dy02e7.js gzip 10.4 kB N/A -
09x_ycos2214h.js gzip 151 B N/A -
0cz1d0mv5g_q7.js gzip 39.4 kB 39.4 kB
0fli3_wppnim5.js gzip 12.9 kB N/A -
0k09jwjeb-tki.js gzip 13.8 kB N/A -
0kb7_ep3r1z0_.js gzip 10.1 kB N/A -
0kw8xgqdrilf6.js gzip 8.56 kB N/A -
0lgndkr1hands.js gzip 49.6 kB N/A -
0ojkk2e654xsc.js gzip 8.59 kB N/A -
0wfoal20dkqj1.js gzip 155 B N/A -
0wxpyd8r-vipl.js gzip 1.47 kB N/A -
0xy2fhla48_rd.js gzip 9.24 kB N/A -
0zx3fp91iid52.js gzip 159 B N/A -
10wqsvi2mgfmi.js gzip 9.82 kB N/A -
16lhqjoqbznyg.js gzip 220 B 220 B
16vepdkipri3r.js gzip 8.51 kB N/A -
17n96uu6y1pxq.js gzip 8.6 kB N/A -
18y4_8-9or0mn.js gzip 8.51 kB N/A -
19410kg_2bl_2.js gzip 156 B N/A -
1elt1qium-r2m.css gzip 115 B 115 B
1gq145j3kps-h.js gzip 8.62 kB N/A -
1li2wvnrlll1x.js gzip 155 B N/A -
1nsh-mbn0e-se.js gzip 8.56 kB N/A -
1tsrrp1tdngti.js gzip 13.3 kB N/A -
2__-e_ym8n788.js gzip 450 B N/A -
22o6xd9_ywdu6.js gzip 233 B N/A -
2587zu9zz3ch0.js gzip 154 B N/A -
25ykkt57gkfew.js gzip 154 B N/A -
2kb7581t3yg4r.js gzip 153 B N/A -
2kvj8yrfznmwx.js gzip 5.69 kB N/A -
2qv7m7xjnokgr.js gzip 8.58 kB N/A -
342ijzvrpe53h.js gzip 2.29 kB N/A -
37pyv-119nldk.js gzip 152 B N/A -
3geqw_3h7k33y.js gzip 156 B N/A -
3ok6wj7wwsorf.js gzip 70.8 kB N/A -
3sfdvnlx2-d2i.js gzip 152 B N/A -
3u-chifslwdvs.js gzip 166 B N/A -
44un3--wmqiyh.js gzip 7.61 kB N/A -
turbopack-09..02ja.js gzip 4.2 kB N/A -
turbopack-0c.._q68.js gzip 4.18 kB N/A -
turbopack-0s..yucr.js gzip 4.19 kB N/A -
turbopack-0x..vpta.js gzip 4.19 kB N/A -
turbopack-10..-d_w.js gzip 4.19 kB N/A -
turbopack-11..dlm2.js gzip 4.18 kB N/A -
turbopack-1k..j62f.js gzip 4.19 kB N/A -
turbopack-27..b9wz.js gzip 4.17 kB N/A -
turbopack-2u..oxs7.js gzip 4.18 kB N/A -
turbopack-37..th14.js gzip 4.18 kB N/A -
turbopack-39..mfcn.js gzip 4.18 kB N/A -
turbopack-3h..4bnr.js gzip 4.18 kB N/A -
turbopack-3i..gib8.js gzip 4.19 kB N/A -
turbopack-3m..bo_z.js gzip 4.19 kB N/A -
07ao55cvtbxdj.js gzip N/A 153 B -
09t9i6o8nvir7.js gzip N/A 49.6 kB -
0arkbdqpxc37i.js gzip N/A 8.6 kB -
0bz-xifewa17d.js gzip N/A 8.63 kB -
0tp80kb9upsmd.js gzip N/A 153 B -
0tsy2vtfmen7f.js gzip N/A 155 B -
0tv67up09u6yz.js gzip N/A 168 B -
0tvekitj587fh.js gzip N/A 8.51 kB -
0y-5s9e_qen41.js gzip N/A 160 B -
0yvk6-wi8e9wh.js gzip N/A 13.3 kB -
0z83a1om5rvtt.js gzip N/A 7.61 kB -
1-jqyfc89tixo.js gzip N/A 1.46 kB -
14t1kneseb8th.js gzip N/A 2.3 kB -
15sb1-dsqfk_j.js gzip N/A 8.59 kB -
1ab2xruymo-oj.js gzip N/A 449 B -
1gt0tm9ba-fkj.js gzip N/A 70.8 kB -
1p-256e9l_n93.js gzip N/A 156 B -
1rexplishteym.js gzip N/A 156 B -
1tu25qtsmfhar.js gzip N/A 9.82 kB -
1vein_gnv3mwr.js gzip N/A 8.56 kB -
1wtjzfc14dkv9.js gzip N/A 154 B -
1wzrm0xjjbzn5.js gzip N/A 10.1 kB -
1xvan__507d2k.js gzip N/A 155 B -
1z3g0uaqtv9_3.js gzip N/A 8.56 kB -
25a1yz7zua29z.js gzip N/A 13.8 kB -
2bi5hx402juv-.js gzip N/A 8.58 kB -
2hy56297fog9u.js gzip N/A 8.52 kB -
2u_rpxq3tzytl.js gzip N/A 233 B -
31pzx_2wlpu4e.js gzip N/A 156 B -
368lim5wq0o0r.js gzip N/A 12.9 kB -
3drqjohogojbw.js gzip N/A 5.69 kB -
3fs484yi1tj7v.js gzip N/A 156 B -
3g8l1m2-o-ewi.js gzip N/A 13.1 kB -
3jmkxsnxg0nrh.js gzip N/A 10.4 kB -
3qacr5lkwv7qz.js gzip N/A 65.5 kB -
3qi06md02f2cn.js gzip N/A 159 B -
3socpyg9nr02a.js gzip N/A 157 B -
3wpp8nvyoj121.js gzip N/A 9.24 kB -
turbopack-0n..mrvy.js gzip N/A 4.17 kB -
turbopack-0p..kynv.js gzip N/A 4.19 kB -
turbopack-0s..7ud3.js gzip N/A 4.18 kB -
turbopack-17..4gpi.js gzip N/A 4.19 kB -
turbopack-1c..9gyb.js gzip N/A 4.19 kB -
turbopack-1e..ccp_.js gzip N/A 4.19 kB -
turbopack-1s..h27x.js gzip N/A 4.19 kB -
turbopack-1t..njk8.js gzip N/A 4.2 kB -
turbopack-29..e4gm.js gzip N/A 4.19 kB -
turbopack-2a..5zpv.js gzip N/A 4.19 kB -
turbopack-2c..tpfn.js gzip N/A 4.19 kB -
turbopack-2k..hjo6.js gzip N/A 4.19 kB -
turbopack-32..3ekq.js gzip N/A 4.19 kB -
turbopack-42..fj8z.js gzip N/A 4.19 kB -
Total 465 kB 465 kB ⚠️ +103 B

Server

Middleware
Canary PR Change
middleware-b..fest.js gzip 712 B 715 B
Total 712 B 715 B ⚠️ +3 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 431 B 433 B
Total 431 B 433 B ⚠️ +2 B

📦 Webpack

Client

Main Bundles
Canary PR Change
2637-HASH.js gzip 4.63 kB N/A -
7724.HASH.js gzip 169 B N/A -
8274-HASH.js gzip 61.4 kB N/A -
8817-HASH.js gzip 5.59 kB N/A -
c3500254-HASH.js gzip 62.8 kB N/A -
framework-HASH.js gzip 59.7 kB 59.7 kB
main-app-HASH.js gzip 254 B 255 B
main-HASH.js gzip 39.4 kB 39.3 kB
webpack-HASH.js gzip 1.68 kB 1.68 kB
5887-HASH.js gzip N/A 5.61 kB -
6522-HASH.js gzip N/A 60.8 kB -
6779-HASH.js gzip N/A 4.63 kB -
8854.HASH.js gzip N/A 169 B -
eab920f9-HASH.js gzip N/A 62.8 kB -
Total 236 kB 235 kB ✅ -640 B
Polyfills
Canary PR Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB
Total 39.4 kB 39.4 kB
Pages
Canary PR Change
_app-HASH.js gzip 193 B 193 B
_error-HASH.js gzip 182 B 182 B
css-HASH.js gzip 333 B 334 B
dynamic-HASH.js gzip 1.81 kB 1.8 kB
edge-ssr-HASH.js gzip 255 B 255 B
head-HASH.js gzip 353 B 349 B 🟢 4 B (-1%)
hooks-HASH.js gzip 384 B 382 B
image-HASH.js gzip 581 B 581 B
index-HASH.js gzip 260 B 259 B
link-HASH.js gzip 2.51 kB 2.51 kB
routerDirect..HASH.js gzip 316 B 318 B
script-HASH.js gzip 386 B 386 B
withRouter-HASH.js gzip 313 B 314 B
1afbb74e6ecf..834.css gzip 106 B 106 B
Total 7.98 kB 7.97 kB ✅ -10 B

Server

Edge SSR
Canary PR Change
edge-ssr.js gzip 126 kB 126 kB
page.js gzip 274 kB 273 kB
Total 399 kB 399 kB ✅ -410 B
Middleware
Canary PR Change
middleware-b..fest.js gzip 619 B 616 B
middleware-r..fest.js gzip 156 B 156 B
middleware.js gzip 44.2 kB 44.2 kB
edge-runtime..pack.js gzip 842 B 842 B
Total 45.8 kB 45.8 kB ⚠️ +29 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 721 B 720 B
Total 721 B 720 B ✅ -1 B
Build Cache
Canary PR Change
0.pack gzip 4.39 MB 4.38 MB 🟢 6.75 kB (0%)
index.pack gzip 114 kB 114 kB
index.pack.old gzip 114 kB 115 kB 🔴 +1.66 kB (+1%)
Total 4.61 MB 4.61 MB ✅ -5.23 kB

🔄 Shared (bundler-independent)

Runtimes
Canary PR Change
app-page-exp...dev.js gzip 347 kB 347 kB
app-page-exp..prod.js gzip 192 kB 192 kB
app-page-tur...dev.js gzip 347 kB 347 kB
app-page-tur..prod.js gzip 192 kB 192 kB
app-page-tur...dev.js gzip 343 kB 343 kB
app-page-tur..prod.js gzip 190 kB 190 kB
app-page.run...dev.js gzip 344 kB 344 kB
app-page.run..prod.js gzip 190 kB 190 kB
app-route-ex...dev.js gzip 77 kB 77 kB
app-route-ex..prod.js gzip 52.5 kB 52.5 kB
app-route-tu...dev.js gzip 77.1 kB 77.1 kB
app-route-tu..prod.js gzip 52.6 kB 52.6 kB
app-route-tu...dev.js gzip 76.7 kB 76.7 kB
app-route-tu..prod.js gzip 52.3 kB 52.3 kB
app-route.ru...dev.js gzip 76.6 kB 76.6 kB
app-route.ru..prod.js gzip 52.3 kB 52.3 kB
dist_client_...dev.js gzip 324 B 324 B
dist_client_...dev.js gzip 326 B 326 B
dist_client_...dev.js gzip 318 B 318 B
dist_client_...dev.js gzip 317 B 317 B
pages-api-tu...dev.js gzip 43.9 kB 43.9 kB
pages-api-tu..prod.js gzip 33.5 kB 33.5 kB
pages-api.ru...dev.js gzip 43.9 kB 43.9 kB
pages-api.ru..prod.js gzip 33.5 kB 33.5 kB
pages-turbo....dev.js gzip 53.3 kB 53.3 kB
pages-turbo...prod.js gzip 39.1 kB 39.1 kB
pages.runtim...dev.js gzip 53.3 kB 53.3 kB
pages.runtim..prod.js gzip 39.1 kB 39.1 kB
server.runti..prod.js gzip 63 kB 63 kB
Total 3.07 MB 3.07 MB ⚠️ +1 B
📎 Tarball URL
https://vercel-packages.vercel.app/next/commits/e0a47d7f42b22dddc5739d415e8114848aba9b10/next

@mmastrac mmastrac marked this pull request as ready for review April 14, 2026 21:16
@mmastrac mmastrac force-pushed the mmastrac/docker-buildx-cache branch from a7a0a54 to b565dfd Compare April 14, 2026 21:22
Base automatically changed from mmastrac/native-artifact-sharing to canary April 15, 2026 15:07
@mmastrac mmastrac force-pushed the mmastrac/docker-buildx-cache branch from 83d6c41 to 7f6b34c Compare April 15, 2026 15:15
@nextjs-bot
Copy link
Copy Markdown
Contributor

nextjs-bot commented Apr 15, 2026

Tests Passed

@mmastrac mmastrac force-pushed the mmastrac/docker-buildx-cache branch from 7f6b34c to 6827a63 Compare April 16, 2026 13:35
@mmastrac mmastrac requested a review from bgw April 16, 2026 15:41
@mmastrac mmastrac force-pushed the mmastrac/docker-buildx-cache branch 2 times, most recently from d417364 to 0eac0fc Compare April 16, 2026 22:02
@mmastrac mmastrac force-pushed the mmastrac/docker-buildx-cache branch from 0eac0fc to 53ed192 Compare April 16, 2026 22:04
@mmastrac mmastrac changed the base branch from canary to graphite-base/92799 April 16, 2026 22:07
@mmastrac mmastrac changed the base branch from graphite-base/92799 to mmastrac/cargo-binstall April 16, 2026 22:07
@mmastrac mmastrac force-pushed the mmastrac/cargo-binstall branch 4 times, most recently from 0ff43ea to 8c16bec Compare April 17, 2026 16:41
@mmastrac mmastrac force-pushed the mmastrac/docker-buildx-cache branch from 53ed192 to bb3f04e Compare April 17, 2026 16:41
Base automatically changed from mmastrac/cargo-binstall to canary April 17, 2026 17:09
Use a reusable docker-buildx action with BuildKit registry cache backed
by the turbo remote cache server. The builder is kept alive between runs
on self-hosted runners so layers stay in BuildKit's local content store.

Removes the old docker-image-cache.js which used zstd-compressed tarballs.
Extract the APT mirror URL from the host's /etc/apt/sources.list
(e.g. Hetzner mirror) and pass it as a build arg to the Dockerfile.
Speeds up apt-get on cache miss when building on Hetzner runners.
@mmastrac mmastrac force-pushed the mmastrac/docker-buildx-cache branch from bb3f04e to e0a47d7 Compare April 17, 2026 17:12
steps:
- name: Resolve cache registry
id: resolve
shell: bash -leo pipefail {0}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems better to just set this to bash?

https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#jobsjob_idstepsshell

Suggested change
shell: bash -leo pipefail {0}
shell: bash

echo "TURBO_TOKEN=${TURBO_TOKEN}" >> "$GITHUB_ENV"

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • It looks like there's already a v4 of this action?
  • Pin it to an exact commit hash.

echo "$CONFIG" | node -e "
const c = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
c.auths = c.auths || {};
c.auths['${REGISTRY}'] = { auth: '${AUTH}' };
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use them as environment variables to avoid escaping issues?

Suggested change
c.auths['${REGISTRY}'] = { auth: '${AUTH}' };
c.auths[process.env.REGISTRY] = { auth: process.env.AUTH };

Comment on lines +67 to +80
- name: Detect host APT mirror
id: apt-mirror
shell: bash
run: |
# Extract the mirror base URL from the host's sources.list.
# Hetzner uses: http://mirror.hetzner.com/ubuntu/packages
# We grab everything before the suite name (jammy, focal, etc).
MIRROR=$(grep -oP 'https?://\S+(?=\s+(focal|jammy|noble)\b)' /etc/apt/sources.list 2>/dev/null | head -1)
if [ -n "$MIRROR" ]; then
echo "url=${MIRROR}" >> "$GITHUB_OUTPUT"
echo "Detected host APT mirror: ${MIRROR}"
else
echo "url=" >> "$GITHUB_OUTPUT"
fi
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I'd rather just hardcode this value, as it's easier to understand if things go wrong.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants