Skip to content

[turbopack] Rebuild the docker build scripts#91799

Merged
mmastrac merged 23 commits into
canaryfrom
mmastrac/faster-link
Mar 24, 2026
Merged

[turbopack] Rebuild the docker build scripts#91799
mmastrac merged 23 commits into
canaryfrom
mmastrac/faster-link

Conversation

@mmastrac
Copy link
Copy Markdown
Contributor

@mmastrac mmastrac commented Mar 22, 2026

Why

The native binary build system uses 3 different napi-rs Docker images that are opaque, can't be customized, and require runtime toolchain downloads. Each CI run downloads compilers and sysroots from scratch, wasting ~5 minutes per build. There's no way to customize the build environment or share toolchains across the 4 Linux targets.

Some smoke tests are added to ensure that node.js can actually load the binaries we build - we don't actually perform much beyond that, just making sure it survives the dynamic linker and correctly exposes the node APIs.

We also are able to enable --icf=all. This appears to (consistently) chop off about ~1-2% of the binary size.

What

Replaces the 3 napi-rs Docker images with a single custom next-swc-builder Dockerfile based on Ubuntu 20.04 that can cross-compile all 4 Linux targets (x86_64/aarch64 × gnu/musl) from either an x86_64 or aarch64 host. All toolchains are baked into the image.

Key changes:

  • docker/native-builder.Dockerfile: Ubuntu 20.04 with clang/lld, GNU cross-sysroots via crossbuild-essential, musl sysroots from musl.cc, Node.js 20, pinned Rust nightly, and cargo-rustflags for flag resolution
  • scripts/docker-native-build.sh: Inner build script that constructs RUSTFLAGS via cargo rustflags --config (merges .cargo/config.toml with cross-compilation overrides), sets up CC/CXX per target, and runs the napi build
  • scripts/docker-native-build.js: Node.js local build orchestrator replacing the bash wrapper, with --quick, --rebuild, --test flags and smoke testing via getTargetTriple()
  • scripts/docker-image-cache.js: Turbo-cached Docker image (save/load with --load for cache hit handling)
  • .cargo/config.toml: Added musl crt-static flag, removed cross-compilation flags (now in build script)
  • CI workflows: Docker image cached via turbo remote cache, build-docker-image turbo task, simplified build_and_deploy.yml

How

All 4 Linux targets use clang as the C compiler + linker driver with gnu-lld-cc flavor (rust-lld does actual linking). Cross-compilation uses --target + --sysroot:

  • GNU targets: Ubuntu multiarch sysroots from crossbuild-essential-{amd64,arm64}
  • Musl targets: musl.cc cross-toolchain sysroots with GCC crt files copied into sysroot lib (works around clang 10's --gcc-toolchain limitation)

RUSTFLAGS are resolved inside the container via cargo rustflags which merges .cargo/config.toml (base flags like -Zunstable-options, musl crt-static) with per-target cross flags passed as --config inline TOML.

The Docker image is cached via turbo's remote cache (~885 MB tar). On cache hit, docker load restores it in seconds. On miss, the full image build takes ~2 minutes.

glibc compatibility

Building on Ubuntu 20.04 (glibc 2.31) ensures broad compatibility. The table below shows the minimum glibc version required by major Linux distributions (source):

Distribution glibc Compatible?
Ubuntu 20.04 (Focal) 2.31 ✅ baseline
Ubuntu 22.04 (Jammy) 2.35
Ubuntu 24.04 (Noble) 2.39
Debian 11 (Bullseye) 2.31
Debian 12 (Bookworm) 2.36
RHEL / AlmaLinux 8 2.28 ❌ EOL May 2029 (security only)
RHEL / AlmaLinux 9 2.34
Amazon Linux 2 2.26 ❌ EOL June 2026
Amazon Linux 2023 2.34
Fedora 40+ 2.39+
Arch Linux 2.41+

@nextjs-bot nextjs-bot added created-by: Turbopack team PRs by the Turbopack team. Turbopack Related to Turbopack with Next.js. labels Mar 22, 2026
@nextjs-bot
Copy link
Copy Markdown
Contributor

nextjs-bot commented Mar 22, 2026

Failing test suites

Commit: 097c7c4 | About building and testing Next.js

pnpm test-start-turbo test/e2e/app-dir/next-config-ts/tsconfig-extends/next-config-ts-tsconfig-extends-esm.test.ts (turbopack) (job)

  • next-config-ts-tsconfig-extends-esm > should support tsconfig extends (ESM) (DD)
Expand output

● next-config-ts-tsconfig-extends-esm › should support tsconfig extends (ESM)

next build failed with code/signal 1

   97 |             if (code || signal)
   98 |               reject(
>  99 |                 new Error(
      |                 ^
  100 |                   `next build failed with code/signal ${code || signal}`
  101 |                 )
  102 |               )

  at ChildProcess.<anonymous> (lib/next-modes/next-start.ts:99:17)

pnpm test-dev-turbo test/development/app-dir/instant-navs-devtools/instant-navs-devtools.test.ts (turbopack) (job)

  • instant-nav-panel > should show loading skeleton during SPA navigation after clicking Start (DD)
  • instant-nav-panel > should auto-open panel on page load when cookie is already set (DD)
Expand output

● instant-nav-panel › should show loading skeleton during SPA navigation after clicking Start

expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false

  161 |           '[data-testid="dynamic-skeleton"]'
  162 |         )
> 163 |         expect(skeleton).toBe(true)
      |                          ^
  164 |       },
  165 |       30000,
  166 |       500

  at toBe (development/app-dir/instant-navs-devtools/instant-navs-devtools.test.ts:163:26)
  at retry (lib/next-test-utils.ts:861:14)
  at Object.<anonymous> (development/app-dir/instant-navs-devtools/instant-navs-devtools.test.ts:158:5)

● instant-nav-panel › should auto-open panel on page load when cookie is already set

page.waitForSelector: Timeout 10ms exceeded.
Call log:
  - waiting for locator('[data-instant-nav-client]') to be visible
    - locator resolved to visible <button class="action-button" data-instant-nav-client="true">…</button>

  545 |
  546 |     return this.startChain(async () => {
> 547 |       const el = await page.waitForSelector(selector, {
      |                             ^
  548 |         timeout,
  549 |         state,
  550 |       })

  at waitForSelector (lib/browsers/playwright.ts:547:29)
  at Playwright._chain (lib/browsers/playwright.ts:677:23)
  at Playwright._chain [as startChain] (lib/browsers/playwright.ts:658:17)
  at Playwright.startChain [as waitForElementByCss] (lib/browsers/playwright.ts:546:17)
  at Playwright.waitForElementByCss (lib/browsers/playwright.ts:439:17)
  at elementByCssInstant (development/app-dir/instant-navs-devtools/instant-navs-devtools.test.ts:41:19)
  at Object.clickStartClientNav (development/app-dir/instant-navs-devtools/instant-navs-devtools.test.ts:180:11)
  at Proxy._chain (lib/browsers/playwright.ts:677:23)
  at Proxy._chain (lib/browsers/playwright.ts:653:17)
  at Proxy.continueChain (lib/browsers/playwright.ts:497:17)
  at click (development/app-dir/instant-navs-devtools/instant-navs-devtools.test.ts:41:68)
  at Object.clickStartClientNav (development/app-dir/instant-navs-devtools/instant-navs-devtools.test.ts:180:11)

pnpm test-start test/e2e/app-dir/use-params/use-params.test.ts (job)

  • use-params > should work for single dynamic param (DD)
  • use-params > should work for nested dynamic params (DD)
  • use-params > should work for catch all params (DD)
  • use-params > should work for single dynamic param client navigating (DD)
  • use-params > should work for nested dynamic params client navigating (DD)
  • use-params > should work on pages router (DD)
  • use-params > shouldn't rerender host component when prefetching (DD)
Expand output

● use-params › should work for single dynamic param

next build failed with code/signal 1

   97 |             if (code || signal)
   98 |               reject(
>  99 |                 new Error(
      |                 ^
  100 |                   `next build failed with code/signal ${code || signal}`
  101 |                 )
  102 |               )

  at ChildProcess.<anonymous> (lib/next-modes/next-start.ts:99:17)

● use-params › should work for nested dynamic params

next build failed with code/signal 1

   97 |             if (code || signal)
   98 |               reject(
>  99 |                 new Error(
      |                 ^
  100 |                   `next build failed with code/signal ${code || signal}`
  101 |                 )
  102 |               )

  at ChildProcess.<anonymous> (lib/next-modes/next-start.ts:99:17)

● use-params › should work for catch all params

next build failed with code/signal 1

   97 |             if (code || signal)
   98 |               reject(
>  99 |                 new Error(
      |                 ^
  100 |                   `next build failed with code/signal ${code || signal}`
  101 |                 )
  102 |               )

  at ChildProcess.<anonymous> (lib/next-modes/next-start.ts:99:17)

● use-params › should work for single dynamic param client navigating

next build failed with code/signal 1

   97 |             if (code || signal)
   98 |               reject(
>  99 |                 new Error(
      |                 ^
  100 |                   `next build failed with code/signal ${code || signal}`
  101 |                 )
  102 |               )

  at ChildProcess.<anonymous> (lib/next-modes/next-start.ts:99:17)

● use-params › should work for nested dynamic params client navigating

next build failed with code/signal 1

   97 |             if (code || signal)
   98 |               reject(
>  99 |                 new Error(
      |                 ^
  100 |                   `next build failed with code/signal ${code || signal}`
  101 |                 )
  102 |               )

  at ChildProcess.<anonymous> (lib/next-modes/next-start.ts:99:17)

● use-params › should work on pages router

next build failed with code/signal 1

   97 |             if (code || signal)
   98 |               reject(
>  99 |                 new Error(
      |                 ^
  100 |                   `next build failed with code/signal ${code || signal}`
  101 |                 )
  102 |               )

  at ChildProcess.<anonymous> (lib/next-modes/next-start.ts:99:17)

● use-params › shouldn't rerender host component when prefetching

next build failed with code/signal 1

   97 |             if (code || signal)
   98 |               reject(
>  99 |                 new Error(
      |                 ^
  100 |                   `next build failed with code/signal ${code || signal}`
  101 |                 )
  102 |               )

  at ChildProcess.<anonymous> (lib/next-modes/next-start.ts:99:17)

pnpm test-start test/e2e/app-dir/next-config-ts/tsconfig-extends/next-config-ts-tsconfig-extends-cjs.test.ts (job)

  • next-config-ts-tsconfig-extends-cjs > should support tsconfig extends (CJS) (DD)
Expand output

● next-config-ts-tsconfig-extends-cjs › should support tsconfig extends (CJS)

next build failed with code/signal 1

   97 |             if (code || signal)
   98 |               reject(
>  99 |                 new Error(
      |                 ^
  100 |                   `next build failed with code/signal ${code || signal}`
  101 |                 )
  102 |               )

  at ChildProcess.<anonymous> (lib/next-modes/next-start.ts:99:17)

@nextjs-bot
Copy link
Copy Markdown
Contributor

nextjs-bot commented Mar 22, 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) 455ms 455ms █▁▃▁▁
Cold (Ready in log) 444ms 443ms █▁▃▁▁
Cold (First Request) 824ms 820ms █▂▃▂▂
Warm (Listen) 456ms 456ms █▁▃▁▁
Warm (Ready in log) 443ms 443ms █▁▃▁▁
Warm (First Request) 342ms 341ms █▁▂▁▁
📦 Dev Server (Webpack) (Legacy)

📦 Dev Server (Webpack)

Metric Canary PR Change Trend
Cold (Listen) 455ms 455ms ▁▁▁█▁
Cold (Ready in log) 438ms 439ms ▁▁▁█▁
Cold (First Request) 1.873s 1.878s ▁▁▂█▃
Warm (Listen) 455ms 456ms ▁▁▁█▁
Warm (Ready in log) 438ms 439ms ▁▁▁█▁
Warm (First Request) 1.877s 1.890s ▁▁▂█▂

⚡ Production Builds

Metric Canary PR Change Trend
Fresh Build 3.845s 3.857s █▁▃▂▁
Cached Build 3.872s 3.860s █▁▃▂▁
📦 Production Builds (Webpack) (Legacy)

📦 Production Builds (Webpack)

Metric Canary PR Change Trend
Fresh Build 14.470s 14.554s ▁▁▁█▁
Cached Build 14.709s 14.716s ▁▁▁█▁
node_modules Size 484 MB 484 MB █████
📦 Bundle Sizes

Bundle Sizes

⚡ Turbopack

Client

Main Bundles
Canary PR Change
0-d~0o3ehhgmw.js gzip 151 B N/A -
0~lwfcrlb4v_9.css gzip 115 B 115 B
00h0nz7r436~l.js gzip 13.3 kB N/A -
00ivb_iunbucu.js gzip 13 kB N/A -
01at~wdgj81ve.js gzip 48.9 kB N/A -
02ku7edzc_wf7.js gzip 450 B N/A -
03~yq9q893hmn.js gzip 39.4 kB 39.4 kB
04z94byop2jge.js gzip 155 B N/A -
05s5bqmu.v.s2.js gzip 70.8 kB N/A -
092lcb3fqrrf9.js gzip 8.52 kB N/A -
0aj~xs1l1g8tg.js gzip 8.53 kB N/A -
0dt88d2.q3puq.js gzip 156 B N/A -
0g5sqjyu0dlae.js gzip 65.7 kB N/A -
0h35gmp9u328z.js gzip 8.54 kB N/A -
0h6fkavebp.iz.js gzip 8.47 kB N/A -
0ino_yf1k3h6k.js gzip 10.4 kB N/A -
0l9ef8qyt48q4.js gzip 161 B N/A -
0lqjp7063d~ts.js gzip 156 B N/A -
0mc16gv2x1bet.js gzip 13.7 kB N/A -
0mkdvwb8sm1cs.js gzip 157 B N/A -
0mncpry_rfn-y.js gzip 7.61 kB N/A -
0moy~uao4dl.m.js gzip 9.19 kB N/A -
0n3yn2kt3mgkf.js gzip 162 B N/A -
0oqyjf21.xfvl.js gzip 169 B N/A -
0q50rtpusjy90.js gzip 2.28 kB N/A -
0smgy2grrrlka.js gzip 8.58 kB N/A -
0svcqoqon1z.7.js gzip 154 B N/A -
0t1dzhdfh0txh.js gzip 215 B 215 B
0vt7pofxnk8in.js gzip 10.1 kB N/A -
0z6jc9z0349ap.js gzip 155 B N/A -
0zid7o0-vupvp.js gzip 225 B N/A -
11mdhajjc6875.js gzip 157 B N/A -
11yo3xfd6b147.js gzip 12.9 kB N/A -
12_8n261pygfq.js gzip 156 B N/A -
13.84hqxl_1p7.js gzip 9.76 kB N/A -
138ltu~qb2ydz.js gzip 158 B N/A -
1554wr-t7p6z-.js gzip 8.55 kB N/A -
15tjst79~qy3_.js gzip 1.46 kB N/A -
15z_v00ne4ud0.js gzip 8.47 kB N/A -
17d_m3p4j9w6r.js gzip 5.62 kB N/A -
17yu~3yiu7d2m.js gzip 8.52 kB N/A -
turbopack-0_..jw30.js gzip 4.15 kB N/A -
turbopack-01..hk.z.js gzip 4.13 kB N/A -
turbopack-01..3tdd.js gzip 4.17 kB N/A -
turbopack-02..cl~l.js gzip 4.15 kB N/A -
turbopack-09..wmtl.js gzip 4.16 kB N/A -
turbopack-0a..hs-0.js gzip 4.16 kB N/A -
turbopack-0f..4bnp.js gzip 4.16 kB N/A -
turbopack-0g..7vlj.js gzip 4.16 kB N/A -
turbopack-0p..6se..js gzip 4.16 kB N/A -
turbopack-0r...~ib.js gzip 4.16 kB N/A -
turbopack-0s..dnao.js gzip 4.16 kB N/A -
turbopack-0x..ivz7.js gzip 4.16 kB N/A -
turbopack-15..u41w.js gzip 4.15 kB N/A -
turbopack-16..~kqj.js gzip 4.15 kB N/A -
0.ig-nh6ddby4.js gzip N/A 153 B -
02ff96.~as-xu.js gzip N/A 157 B -
03t__~.5lvgeu.js gzip N/A 5.62 kB -
04d6ll75jqx3r.js gzip N/A 9.19 kB -
04wavr--oh-1-.js gzip N/A 155 B -
0583exyh-yhc7.js gzip N/A 9.76 kB -
072lv63r8dcz~.js gzip N/A 8.58 kB -
075t9dxgbf0m8.js gzip N/A 13.7 kB -
0873k5691ee0i.js gzip N/A 70.8 kB -
09123-xgm97yo.js gzip N/A 160 B -
0a3drqm~aryl6.js gzip N/A 153 B -
0ar1~bwpezfgw.js gzip N/A 13.3 kB -
0c99mq1ez2bke.js gzip N/A 450 B -
0cq-cmde_ws6u.js gzip N/A 8.47 kB -
0fwf102w10o9~.js gzip N/A 8.52 kB -
0gtmn.q_j1v5r.js gzip N/A 10.4 kB -
0h5~v-tahitcf.js gzip N/A 10.1 kB -
0i85sm0i~_x1y.js gzip N/A 48.8 kB -
0ka9wyuwc0va-.js gzip N/A 154 B -
0m8yz2-y.owhu.js gzip N/A 7.6 kB -
0nclq9z6yzzm5.js gzip N/A 1.46 kB -
0nga-9kug7bgp.js gzip N/A 154 B -
0nzumcogektg7.js gzip N/A 8.55 kB -
0p5sjual.nuis.js gzip N/A 13 kB -
0pet9ixg7-64s.js gzip N/A 149 B -
0pzv1cr_lc8sc.js gzip N/A 154 B -
0s.c-cn5eebrx.js gzip N/A 8.47 kB -
0t4u4gi13w~ge.js gzip N/A 65.7 kB -
0tna7lg6q4zne.js gzip N/A 12.9 kB -
0votdfxr5fb5u.js gzip N/A 2.28 kB -
0ykl9bs_qj.5..js gzip N/A 8.52 kB -
0zfen0tnxp4gh.js gzip N/A 8.55 kB -
10wkq1h9jzkg..js gzip N/A 225 B -
12s.i1.5kfw6p.js gzip N/A 168 B -
13yp0tf_.vo3_.js gzip N/A 152 B -
143nm3aj63v.8.js gzip N/A 152 B -
149ndfh8zfcaz.js gzip N/A 8.53 kB -
17vn26efzi_wl.js gzip N/A 154 B -
turbopack-01..1zy5.js gzip N/A 4.15 kB -
turbopack-04..ylsp.js gzip N/A 4.15 kB -
turbopack-05..2tc..js gzip N/A 4.16 kB -
turbopack-0g..j7lx.js gzip N/A 4.15 kB -
turbopack-0g..sg37.js gzip N/A 4.16 kB -
turbopack-0h..1v_h.js gzip N/A 4.16 kB -
turbopack-0i..qamy.js gzip N/A 4.17 kB -
turbopack-0o..hr_c.js gzip N/A 4.16 kB -
turbopack-0t..0nu2.js gzip N/A 4.16 kB -
turbopack-0v..9.j3.js gzip N/A 4.16 kB -
turbopack-0v..v9_z.js gzip N/A 4.16 kB -
turbopack-0x..yhs..js gzip N/A 4.16 kB -
turbopack-0y..l8a..js gzip N/A 4.13 kB -
turbopack-13..jmn~.js gzip N/A 4.16 kB -
Total 463 kB 463 kB ✅ -43 B

Server

Middleware
Canary PR Change
middleware-b..fest.js gzip 713 B 711 B
Total 713 B 711 B ✅ -2 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 431 B 430 B
Total 431 B 430 B ✅ -1 B

📦 Webpack

Client

Main Bundles
Canary PR Change
5528-HASH.js gzip 5.54 kB N/A -
6280-HASH.js gzip 60.6 kB N/A -
6335.HASH.js gzip 169 B N/A -
912-HASH.js gzip 4.59 kB N/A -
e8aec2e4-HASH.js gzip 62.7 kB N/A -
framework-HASH.js gzip 59.7 kB 59.7 kB
main-app-HASH.js gzip 256 B 255 B
main-HASH.js gzip 39.3 kB 39.2 kB
webpack-HASH.js gzip 1.68 kB 1.68 kB
262-HASH.js gzip N/A 4.59 kB -
2889.HASH.js gzip N/A 169 B -
5602-HASH.js gzip N/A 5.55 kB -
6948ada0-HASH.js gzip N/A 62.7 kB -
9544-HASH.js gzip N/A 61.3 kB -
Total 235 kB 235 kB ⚠️ +696 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 194 B 194 B
_error-HASH.js gzip 183 B 180 B 🟢 3 B (-2%)
css-HASH.js gzip 331 B 330 B
dynamic-HASH.js gzip 1.81 kB 1.81 kB
edge-ssr-HASH.js gzip 256 B 256 B
head-HASH.js gzip 351 B 352 B
hooks-HASH.js gzip 384 B 383 B
image-HASH.js gzip 580 B 581 B
index-HASH.js gzip 260 B 260 B
link-HASH.js gzip 2.51 kB 2.51 kB
routerDirect..HASH.js gzip 320 B 319 B
script-HASH.js gzip 386 B 386 B
withRouter-HASH.js gzip 315 B 315 B
1afbb74e6ecf..834.css gzip 106 B 106 B
Total 7.98 kB 7.98 kB ✅ -1 B

Server

Edge SSR
Canary PR Change
edge-ssr.js gzip 125 kB 125 kB
page.js gzip 270 kB 270 kB
Total 395 kB 395 kB ⚠️ +224 B
Middleware
Canary PR Change
middleware-b..fest.js gzip 617 B 614 B
middleware-r..fest.js gzip 156 B 155 B
middleware.js gzip 44 kB 43.8 kB
edge-runtime..pack.js gzip 842 B 842 B
Total 45.6 kB 45.4 kB ✅ -193 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 715 B 718 B
Total 715 B 718 B ⚠️ +3 B
Build Cache
Canary PR Change
0.pack gzip 4.33 MB 4.33 MB
index.pack gzip 110 kB 112 kB 🔴 +1.73 kB (+2%)
index.pack.old gzip 110 kB 109 kB
Total 4.55 MB 4.56 MB ⚠️ +2.96 kB

🔄 Shared (bundler-independent)

Runtimes
Canary PR Change
app-page-exp...dev.js gzip 334 kB 334 kB
app-page-exp..prod.js gzip 182 kB 182 kB
app-page-tur...dev.js gzip 334 kB 334 kB
app-page-tur..prod.js gzip 181 kB 181 kB
app-page-tur...dev.js gzip 330 kB 330 kB
app-page-tur..prod.js gzip 179 kB 179 kB
app-page.run...dev.js gzip 331 kB 331 kB
app-page.run..prod.js gzip 180 kB 180 kB
app-route-ex...dev.js gzip 76.2 kB 76.2 kB
app-route-ex..prod.js gzip 51.8 kB 51.8 kB
app-route-tu...dev.js gzip 76.2 kB 76.2 kB
app-route-tu..prod.js gzip 51.9 kB 51.9 kB
app-route-tu...dev.js gzip 75.8 kB 75.8 kB
app-route-tu..prod.js gzip 51.6 kB 51.6 kB
app-route.ru...dev.js gzip 75.8 kB 75.8 kB
app-route.ru..prod.js gzip 51.6 kB 51.6 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.4 kB 43.4 kB
pages-api-tu..prod.js gzip 33 kB 33 kB
pages-api.ru...dev.js gzip 43.4 kB 43.4 kB
pages-api.ru..prod.js gzip 33 kB 33 kB
pages-turbo....dev.js gzip 52.8 kB 52.8 kB
pages-turbo...prod.js gzip 38.6 kB 38.6 kB
pages.runtim...dev.js gzip 52.8 kB 52.8 kB
pages.runtim..prod.js gzip 38.6 kB 38.6 kB
server.runti..prod.js gzip 62.5 kB 62.5 kB
Total 2.96 MB 2.96 MB ⚠️ +1 B
📎 Tarball URL
https://vercel-packages.vercel.app/next/commits/097c7c4c83f85c9d6d5ecd0e10bb9259de11f8ca/next

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Mar 22, 2026

Merging this PR will improve performance by 3.99%

⚡ 3 improved benchmarks
✅ 14 untouched benchmarks
⏩ 3 skipped benchmarks1

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation app-page-turbo.runtime.prod.js[full] 647.7 ms 623.7 ms +3.84%
Simulation packages-bundle.js[full] 992.1 ms 958.9 ms +3.46%
Simulation react-dom-client.development.js[full] 409.2 ms 393.5 ms +3.99%

Comparing mmastrac/faster-link (7fdbd98) with canary (9fdd5bc)

Open in CodSpeed

Footnotes

  1. 3 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

Comment thread scripts/docker-native-build.js Outdated
@mmastrac mmastrac force-pushed the mmastrac/faster-link branch 2 times, most recently from a2ecffd to c2ba839 Compare March 23, 2026 22:28
Copy link
Copy Markdown
Contributor Author

mmastrac commented Mar 23, 2026

Comment thread scripts/docker-native-build.sh
Comment thread scripts/docker-image-cache.js Outdated
Comment on lines +2 to +3
// @ts-check
//
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.

We use https://npmx.dev/package/tsx to call scripts/pack-next.ts. We could potentially do the same here.

We'll be able to drop tsx in Next 17 when we drop Node 20, since Node 22 supports --experimental-strip-types.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I made the change and then realized that the CI doesn't have tsx installed :/ I can revisit easily later on.

Comment on lines +23 to +26
const { execSync } = require('child_process')
const path = require('path')
const fs = require('fs')
const os = require('os')
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.

This could be an .mjs file (or .ts as mentioned above) and use ESM imports. I don't think we have a good reason anymore to use cjs in scripts.

Comment on lines +51 to +54
execSync(
`docker build -t ${IMAGE_NAME} -f ${path.join(REPO_ROOT, 'scripts/native-builder.Dockerfile')} ${ctx}`,
{ stdio: 'inherit' }
)
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.

  • Nit: Prefer spawnSync over execSync to avoid the extra shell and possible shell escaping issues.
  • Other scripts use execa (it's a really old version though), so you could use that if you prefer. https://npmx.dev/package/execa/v/2.0.3

Comment thread scripts/native-builder.Dockerfile Outdated
Comment thread scripts/native-builder.Dockerfile Outdated
@mmastrac mmastrac force-pushed the mmastrac/faster-link branch from 41d1fb8 to 5ebf44d Compare March 24, 2026 18:25
- Add --icf=all to Windows config (already uses rust-lld)
- Replace multi-stage node:20-slim copy with nodesource apt repo install
- Simplify Dockerfile (single stage, no COPY --from)
- Add rust-lld linker and --icf=all for macOS targets in .cargo/config.toml
- Replace manual switch/case arg parsing with Node.js util.parseArgs
  (zero dependencies, available since Node 16.17)
@mmastrac mmastrac force-pushed the mmastrac/faster-link branch from 5ebf44d to 097c7c4 Compare March 24, 2026 18:28
@mmastrac mmastrac enabled auto-merge (squash) March 24, 2026 18:30
@mmastrac mmastrac disabled auto-merge March 24, 2026 19:07
@mmastrac mmastrac merged commit b163a8b into canary Mar 24, 2026
158 of 168 checks passed
@mmastrac mmastrac deleted the mmastrac/faster-link branch March 24, 2026 19:07
@github-actions github-actions Bot added the locked label Apr 8, 2026
@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Apr 8, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

created-by: Turbopack team PRs by the Turbopack team. locked Turbopack Related to Turbopack with Next.js. type: next

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants