Turbopack: use module graph for NFT - #92901
Merged
Merged
Conversation
Member
Author
This stack of pull requests is managed by Graphite. Learn more about stacking. |
mischnic
force-pushed
the
mischnic/nft-module-graph
branch
3 times, most recently
from
April 20, 2026 14:09
467a71d to
affcef5
Compare
mischnic
force-pushed
the
mischnic/nft-module-graph
branch
5 times, most recently
from
April 27, 2026 07:54
a211af5 to
3c9e89d
Compare
Contributor
Stats skippedCommit: a85b4f7 |
Contributor
Tests PassedCommit: ced85b3 |
mischnic
force-pushed
the
mischnic/nft-module-graph
branch
from
April 27, 2026 13:17
3c9e89d to
875593b
Compare
mischnic
changed the base branch from
graphite-base/92901
to
mischnic/fix-side-effect-edge-removal
April 27, 2026 13:17
This was referenced Apr 27, 2026
mischnic
force-pushed
the
mischnic/fix-side-effect-edge-removal
branch
from
April 28, 2026 11:02
9f6dd11 to
d83638e
Compare
mischnic
force-pushed
the
mischnic/nft-module-graph
branch
from
April 28, 2026 11:02
c287212 to
05f5347
Compare
mischnic
changed the base branch from
mischnic/fix-side-effect-edge-removal
to
graphite-base/92901
April 28, 2026 12:11
mischnic
force-pushed
the
mischnic/nft-module-graph
branch
from
April 28, 2026 12:11
05f5347 to
08de2b2
Compare
mischnic
changed the base branch from
graphite-base/92901
to
mischnic/iter_reachable_nodes
April 28, 2026 12:11
mischnic
marked this pull request as ready for review
April 28, 2026 13:26
mischnic
changed the base branch from
mischnic/remove-unused-references
to
graphite-base/92901
April 29, 2026 10:43
mischnic
force-pushed
the
graphite-base/92901
branch
from
April 29, 2026 10:43
e13b7ae to
5eec78a
Compare
mischnic
force-pushed
the
mischnic/nft-module-graph
branch
from
April 29, 2026 12:58
5221241 to
adfd39a
Compare
mischnic
force-pushed
the
mischnic/nft-module-graph
branch
2 times, most recently
from
April 29, 2026 13:24
bd05675 to
8eddf37
Compare
lukesandberg
reviewed
May 6, 2026
lukesandberg
reviewed
May 6, 2026
lukesandberg
reviewed
May 7, 2026
lukesandberg
approved these changes
May 7, 2026
mischnic
force-pushed
the
mischnic/nft-module-graph
branch
2 times, most recently
from
May 13, 2026 15:48
5ebe664 to
fb3e6e5
Compare
lukesandberg
approved these changes
May 13, 2026
mischnic
force-pushed
the
mischnic/nft-module-graph
branch
from
May 28, 2026 09:57
62b6a8b to
a85b4f7
Compare
mischnic
force-pushed
the
mischnic/nft-module-graph
branch
from
May 28, 2026 12:47
a85b4f7 to
ced85b3
Compare
Member
Author
mischnic
pushed a commit
that referenced
this pull request
Jul 16, 2026
#95815 refactored the NFT flow and ended up only tracing the RSC template and it's subgraph. Not the server actions loader module whose module graph is completely separate. --- Clauded. Attempts to fix #95130 (reply in thread). --- <details> ## Summary Fixes the NFT tracing regression behind #95815 and the deploy failures reported in #87737 (comment). Since the 16.3 NFT rewrite (#94224 / #92901), a `serverExternalPackages` entry that is imported **only from a `'use server'` action referenced by a client component** ends up in the route's trace as the content-hashed alias symlink (`.next/node_modules/<pkg>-<hash>`) **without the store files the symlink points to**. Any output assembled from the traces (Vercel lambdas, `output: 'standalone'`) then contains a dangling symlink, and invoking the action throws `Failed to load external module <pkg>-<hash>` (HTTP 500). 16.2.9 traces both. Both CJS and ESM externals are affected, with any package manager — the ESM/bun/monorepo framing in the issue reports was a coincidence of which packages were only reachable through actions. The cause: `AppEndpoint::trace_result` started the trace DFS only from `rsc_entry`, but the server actions loader is a separate module-graph entry (`additional_entries`). It is chunked into the endpoint output (which emits the alias symlink via the chunk's output assets), yet its subgraph — including the externals' traced target files — was never visited by the tracer. `trace_endpoint` now accepts multiple entry modules and the app endpoint passes the actions loader alongside `rsc_entry`. The test observes the user-visible failure: it builds with `output: 'standalone'`, deletes everything except the standalone output (so only traced files are available, like a deployed lambda), runs `server.js`, and invokes the server action in a browser. Without the fix the action fails with `Failed to load external module lodash-<hash>`; on 16.2.9 the same fixture responds with the action result. Note the fixture must not import the externals from any other route: the standalone output is the union of all route traces, so a route that traces them correctly would mask the missing entries. ## Verification - `pnpm test-start-turbo test/production/standalone-mode/server-action-externals/standalone-mode-server-action-externals.test.ts` — fails without the fix (`Failed to load external module lodash-fb78ad0536ffcdab` from the standalone server), passes with it. The equivalent standalone flow on `next@16.2.9` returns the action result with HTTP 200. - `pnpm test-start-turbo test/e2e/externals-transitive/externals-transitive.test.ts` - `pnpm test-start-turbo test/production/standalone-mode/server-actions/standalone-mode-server-actions.test.ts` <!-- NEXT_JS_LLM --> </details>
m-kawafuji
pushed a commit
to m-kawafuji/next.js
that referenced
this pull request
Aug 8, 2026
- [x] skip traced edges properly in all graph traversals
- [x] iter_nodes and enumerate_nodes include the traced modules
- [x] Don't propagate is_self_async inside of traced references as a perf optimization
- [x] fix performance
- [x] validate that NFT JSON files are identical
- [x] ~~validate/adjust bundle analyzer output~~ will be in followup
- [x] audit `fn chunking_type()` changes
Benchmark:
```
* ced85b3 - (2 weeks ago) refactor - Niklas Mischkulnig (HEAD -> mischnic/nft-module-graph, origin/mischnic/nft-module-graph)
TURBOPACK_PERSISTENT_CACHE=0 NEXT_TURBOPACK_TRACING= pnpm next build 334.96s user 44.57s system 788% cpu 48.152 total
TURBOPACK_PERSISTENT_CACHE=0 NEXT_TURBOPACK_TRACING= pnpm next build 343.39s user 42.61s system 809% cpu 47.659 total
* 5edf482 - (77 minutes ago) v16.3.0-canary.32 - next-js-bot[bot] (HEAD, tag: v16.3.0-canary.32)
TURBOPACK_PERSISTENT_CACHE=0 NEXT_TURBOPACK_TRACING= pnpm next build 333.42s user 43.57s system 712% cpu 52.877 total
TURBOPACK_PERSISTENT_CACHE=0 NEXT_TURBOPACK_TRACING= pnpm next build 332.95s user 43.15s system 791% cpu 47.515 total
TURBOPACK_PERSISTENT_CACHE=0 NEXT_TURBOPACK_TRACING= pnpm next build 337.59s user 41.28s system 771% cpu 49.117 total
TURBOPACK_PERSISTENT_CACHE=0 NEXT_TURBOPACK_TRACING= pnpm next build 335.25s user 45.53s system 718% cpu 52.975 total
```
<details>
<summary>Previous benchmarks</summary>
```
52212418699f362904d64c08e544d4994e8d27fa mischnic/nft-module-graph
pnpm next build 371.41s user 66.39s system 737% cpu 59.353 total
pnpm next build 380.13s user 59.62s system 751% cpu 58.548 total
pnpm next build 374.25s user 60.55s system 761% cpu 57.102 total
8e4cfc5 canary
pnpm next build 370.77s user 53.89s system 762% cpu 55.725 total
pnpm next build 383.16s user 55.61s system 744% cpu 58.921 total
pnpm next build 382.34s user 53.51s system 757% cpu 57.512 total
pnpm next build 381.15s user 54.50s system 751% cpu 57.943 total
```
```
b0d5411a79 mischnic/nft-module-graph
pnpm next build --experimental-build-mode=compil 368.75s user 62.05s system 749% cpu 57.445 total
pnpm next build --experimental-build-mode=compil 368.95s user 58.42s system 763% cpu 56.004 total
0e3ad27 mischnic/nft-module-graph
pnpm next build --experimental-build-mode=compil 369.48s user 60.62s system 748% cpu 57.494 total
pnpm next build --experimental-build-mode=compil 374.89s user 52.27s system 730% cpu 58.449 total
pnpm next build --experimental-build-mode=compil 375.02s user 52.89s system 747% cpu 57.274 total
f37073e mischnic/speed-next-dynamic-map
pnpm next build --experimental-build-mode=compil 389.58s user 55.98s system 704% cpu 1:03.21 total
e599b11e2d6b09a92600cfca6d9b338ed1f7537d mischnic/fix-side-effect-edge-removal
pnpm next build --experimental-build-mode=compil 386.60s user 53.34s system 720% cpu 1:01.09 total
f68f70b canary
pnpm next build --experimental-build-mode=compil 387.46s user 53.72s system 738% cpu 59.716 total
pnpm next build --experimental-build-mode=compil 390.33s user 53.54s system 734% cpu 1:00.43 total
pnpm next build --experimental-build-mode=compil 385.33s user 56.55s system 722% cpu 1:01.18 total
pnpm next build --experimental-build-mode=compil 386.49s user 56.44s system 726% cpu 1:00.96 total
```
```
b1ed455 origin/mischnic/nft-module-graph
pnpm next build --experimental-build-mode=compile 467.28s user 75.24s system 791% cpu 1:08.56 total
pnpm next build --experimental-build-mode=compile 465.00s user 76.80s system 831% cpu 1:05.20 total
pnpm next build --experimental-build-mode=compile 473.86s user 70.73s system 790% cpu 1:08.90 total
3cb77c8 canary
pnpm next build --experimental-build-mode=compile 367.91s user 58.06s system 726% cpu 58.672 total
pnpm next build --experimental-build-mode=compile 362.97s user 57.68s system 746% cpu 56.379 total
pnpm next build --experimental-build-mode=compile 364.59s user 57.01s system 724% cpu 58.167 total
```
</details>
m-kawafuji
pushed a commit
to m-kawafuji/next.js
that referenced
this pull request
Aug 8, 2026
) vercel#95815 refactored the NFT flow and ended up only tracing the RSC template and it's subgraph. Not the server actions loader module whose module graph is completely separate. --- Clauded. Attempts to fix vercel#95130 (reply in thread). --- <details> ## Summary Fixes the NFT tracing regression behind vercel#95815 and the deploy failures reported in vercel#87737 (comment). Since the 16.3 NFT rewrite (vercel#94224 / vercel#92901), a `serverExternalPackages` entry that is imported **only from a `'use server'` action referenced by a client component** ends up in the route's trace as the content-hashed alias symlink (`.next/node_modules/<pkg>-<hash>`) **without the store files the symlink points to**. Any output assembled from the traces (Vercel lambdas, `output: 'standalone'`) then contains a dangling symlink, and invoking the action throws `Failed to load external module <pkg>-<hash>` (HTTP 500). 16.2.9 traces both. Both CJS and ESM externals are affected, with any package manager — the ESM/bun/monorepo framing in the issue reports was a coincidence of which packages were only reachable through actions. The cause: `AppEndpoint::trace_result` started the trace DFS only from `rsc_entry`, but the server actions loader is a separate module-graph entry (`additional_entries`). It is chunked into the endpoint output (which emits the alias symlink via the chunk's output assets), yet its subgraph — including the externals' traced target files — was never visited by the tracer. `trace_endpoint` now accepts multiple entry modules and the app endpoint passes the actions loader alongside `rsc_entry`. The test observes the user-visible failure: it builds with `output: 'standalone'`, deletes everything except the standalone output (so only traced files are available, like a deployed lambda), runs `server.js`, and invokes the server action in a browser. Without the fix the action fails with `Failed to load external module lodash-<hash>`; on 16.2.9 the same fixture responds with the action result. Note the fixture must not import the externals from any other route: the standalone output is the union of all route traces, so a route that traces them correctly would mask the missing entries. ## Verification - `pnpm test-start-turbo test/production/standalone-mode/server-action-externals/standalone-mode-server-action-externals.test.ts` — fails without the fix (`Failed to load external module lodash-fb78ad0536ffcdab` from the standalone server), passes with it. The equivalent standalone flow on `next@16.2.9` returns the action result with HTTP 200. - `pnpm test-start-turbo test/e2e/externals-transitive/externals-transitive.test.ts` - `pnpm test-start-turbo test/production/standalone-mode/server-actions/standalone-mode-server-actions.test.ts` <!-- NEXT_JS_LLM --> </details>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

validate/adjust bundle analyzer outputwill be in followupfn chunking_type()changesBenchmark:
Previous benchmarks