Commit Graph
34786 Commits
Author SHA1 Message Date
JosephandGitHub c0a7b91bec cna: use LayoutProps helper in TS layout templates (#95675)
Update create-next-app templates to use `LayoutProps`
2026-07-21 02:17:52 +02:00
next-js-bot[bot]andGitHub 4dea35dbd2 v16.3.0-canary.91 v16.3.0-canary.91 2026-07-20 23:34:46 +00:00
Marcos HernanzandGitHub 6c5e0bbd74 [turbopack] Skip redundant top-level root updates (#95903)
## Summary

- skip the redundant aggregation-root update when
`ConnectChildOperation` reconnects an already constructed top-level task
that is already an aggregation root
- avoid entering the aggregation operation loop when no update was
queued

The fast path is intentionally narrow. It applies only when the
connection has no parent, the task has materialized output, and the
task's aggregation number is already the root sentinel. The task may
still be dirty and need to run; this only skips an idempotent
aggregation update. A task that is not yet a root still goes through the
normal update on its first top-level connection. Tasks without output
are still scheduled, parented connections retain their activeness and
aggregation updates, and transient-state boundaries are unchanged.

## Findings

The earlier scheduler experiment has been removed completely.

The apparent benefit from keeping a worker alive with
`std::thread::yield_now()` was specific to the benchmark topology:
Criterion's `Runtime::block_on` caller runs outside the single-worker
Tokio runtime, so that external caller can enqueue the next root task
while the runtime worker is yielding at the OS level. The sole Tokio
worker itself cannot produce work during that loop. In normal
scheduling, tasks typically enqueue their children before the current
job exits, and a multi-worker runtime can start another worker when it
is below its target. That does not justify burning CPU in an idle
worker, nor replacing the loop with an async-yield retry loop.

The retained optimization is independent of that artifact. An already
constructed top-level task that is already rooted has no new root update
to perform; re-enqueuing the idempotent update only forces the operation
executor through unnecessary suspend points.

This PR now contains no changes to `priority_runner`, worker lifetime,
busy waiting, OS-thread yielding, async yielding, HMR, filesystem
watching, or documentation.

## Benchmark results

The benchmark source, runtime construction, profiles, allocator,
toolchain, and worker count were unchanged. Frozen baseline and
candidate executables were run adjacently in alternating order. Three
focused pairs met the control-drift threshold; one pair was excluded
before analysis because its Tokio control moved by more than 2%.

Median candidate changes across the valid pairs:

| Case | Change |
| --- | ---: |
| direct control | +0.071% |
| Tokio control | -0.177% |
| uncached task | +1.266% |
| cached, same key | -37.868% |
| cached, different keys | -26.783% |

The complete all-duration local sweeps did not meet the control
thresholds, so their task measurements are deliberately not cited. Fresh
remote CodeSpeed and Stats results are the authoritative guardrail for
the full benchmark.

## Verification

- `cargo fmt --all -- --check`
- `cargo clippy -p turbo-tasks-backend --all-targets -- -D warnings -A
deprecated`
- `cargo test -p turbo-tasks-backend`
- `pnpm build-all`
- two-engine autoreview after the final changes, with no findings
- Not run: `pnpm --filter=next dev` (the final diff is Rust-only and was
covered by the full bootstrap build and Cargo suites)
2026-07-20 16:28:18 -07:00
Sam PoderandGitHub e71934a17f [turbopack] Drop unused exports from a CJS module (#95716)
This PR introduces two new things: a pass of the analyzer that
recognises exports from CJS modules (in the form of `exports.foo`, see
`analyze_cjs_exports`) and then a CodeGen that reads `export_usage_info`
to remove CJS exports that are not used.

This PR does not add anything additionally to `export_usage_info`, so
this means that we only trim from modules that are imported with `import
{ foo } from "bar"`. The CodeGen depends on the output of
`analyze_cjs_exports` for the locations of exports, whether it is safe
to drop exports (its pretty conservative), and also whether `__esModule`
is present.
2026-07-20 15:51:46 -07:00
Benjamin WoodruffandGitHub 5fe8c690eb Turbopack: Simplify parent directory creation retry loop logic (#95835)
Noticed while reading through the symlink code.

The symlink logic had some clever `ErrorKind::AlreadyExists` logic that
folded the retry into the main retry loop, but we still had a separate
retry loop for after handling `ErrorKind::NotFound`. This folds the
loops together.

I hand-implemented the symlink version of this and had opus port it to
the non-symlink version.
2026-07-20 14:10:25 -07:00
Marcos HernanzandGitHub cc57d6521d Run Rust doctests in CI (#95911)
## Summary

Run all Rust workspace doctests as part of the existing Turbo-cached
cargo unit test task so future documentation regressions fail CI without
adding an uncached workspace build.

## Verification

- `cargo test --workspace --doc --profile=release-with-assertions
--no-fail-fast`
- Not run: `pnpm --filter=@next/swc test-cargo-unit` (`cargo-nextest` is
installed in CI but unavailable locally; the new doctest suffix passed
independently)

<!-- NEXT_JS_LLM -->
2026-07-20 13:22:20 -07:00
Aurora ScharffandGitHub 03701bee74 docs: add 'Set up your editor' to the installation guide (#95928)
## Summary

<img width="1304" height="1546" alt="CleanShot 2026-07-19 at 01 07
57@2x"
src="https://github.com/user-attachments/assets/b9a6a7c9-dc95-42d5-9cce-f29e6d869d92"
/>


Adds a "Set up your editor" section to the App Router installation
guide. The App Router names files by convention (`page.tsx`,
`layout.tsx`, `route.ts`), so an editor quickly fills with same-named
tabs. This section shows how to tell them apart with VS Code / Cursor
custom editor labels, labeled two folders deep so dynamic routes like
`blog/[id]/page.tsx` do not all collapse to the same `[id]` label. It
includes:

- A copy-paste `.vscode/settings.json` config
(`workbench.editor.customLabels.patterns`) for setting it up by hand.
- A copyable prompt that points a coding agent back at this section to
apply the config, including adapting it to other editors.
- A good-to-know that JetBrains IDEs (WebStorm, IntelliJ) do this
automatically.

## Verification

- Previewed locally against the docs site: the section renders (HTTP
200), with the config block, the prompt card, and the good-to-know all
rendering correctly.

<!-- NEXT_JS_LLM_PR -->
2026-07-20 21:55:53 +02:00
Manoraj KandGitHub 8669b07f19 fix(cms-contentful): await draftMode() and use Promise<> params type (#95631)
### What?
Fix the `cms-contentful` example to use the async APIs introduced in
Next.js 15:
- Await `draftMode()` in `app/page.tsx`, `app/posts/[slug]/page.tsx`,
and
  `app/api/disable-draft/route.ts`
  - Update `params` type to `Promise<{ slug: string }>` and await it in
  `app/posts/[slug]/page.tsx`

### Why?
In Next.js 15, `draftMode()` from `next/headers` became async and must
be awaited.
Page `params` are also now typed as a `Promise`. The example was using
the old
synchronous patterns, causing the build to fail and the app to not work
when running against the latest
version of Next.js -- this example project uses latest version of
next.js in the package.json.

### How?
Awaited `draftMode()` at each call site and updated the `params` type
signature to
  `Promise<{ slug: string }>` with a corresponding `await`.

Closes NEXT-
Fixes #
2026-07-20 18:18:38 +02:00
Niklas MischkulnigandGitHub d3e41fb496 Move outputHashSalt out of experimental (#95840)
Keep reading `config.experimental.outputHashSalt` for now to not break
existing adapters until they are migrated.
2026-07-20 16:34:58 +02:00
Niklas MischkulnigandGitHub 756d6dc9ea Move immutable static assets config option out of experimental (#95351)
Keep reading `config.experimental.supportsImmutableAssets` for now to
not break existing adapters until they are migrated.

Closes NAR-868
2026-07-20 15:35:14 +02:00
Sebastian "Sebbie" SilbermannandGitHub 094dccb25f [instant] Let dev-server requests bypass the fetch lock (#95761) 2026-07-20 10:02:37 +00:00
next-js-bot[bot]andGitHub 163e45e401 v16.3.0-canary.90 v16.3.0-canary.90 2026-07-19 23:34:16 +00:00
Vercel Release BotGitHubnext-js-bot[bot] <279046576+next-js-bot[bot]@users.noreply.github.com>
c246ba9f07 Upgrade React from 7023f501-20260714 to 172742b4-20260716 (#95901)
Co-authored-by: next-js-bot[bot] <279046576+next-js-bot[bot]@users.noreply.github.com>
2026-07-20 01:23:55 +02:00
next-js-bot[bot]andGitHub 0491db047b v16.3.0-canary.89 v16.3.0-canary.89 2026-07-17 23:32:07 +00:00
Marcos HernanzandGitHub 7e817e863b Fix Rust doctest failures (#95909)
## Summary

- Fix Rust documentation examples so workspace doctests compile
successfully.
- Mark incomplete illustrative snippets as ignored while keeping
runnable examples checked.
- Update stale imports and API usage, and classify directory trees as
text.

## Verification

- cargo fmt --all -- --check
- cargo test --workspace --doc --no-fail-fast
- autoreview --mode local --stream-engine-output (Codex + Claude: 0
findings)
2026-07-17 15:39:16 -07:00
Sam PoderandGitHub 42ccb2eede [turbopack] Clean up server_chunking_context (#95908)
https://github.com/vercel/next.js/pull/95539/changes#r3598998062
2026-07-17 21:44:26 +00:00
Sam PoderandGitHub 20f5809320 [turbopack] Don't SSR on pages only navigated to through a soft nav (#95539)
This PR essentially implements:
https://github.com/vercel/next.js/pull/95539#discussion_r3555050929.
Will add more a description soon.
2026-07-17 13:10:54 -07:00
Jude GaoandGitHub 50f367bc21 Package skills/ as a Claude Code plugin (#95907)
#94877 removed the embedded plugin marketplace because its plugin
carried copies of skills that drifted from `skills/`. This re-adds
plugin packaging without duplicating any content: `skills/` itself is
the plugin root. `skills/.claude-plugin/plugin.json` sets `"skills":
["./"]` so the four skills at `skills/*/SKILL.md` are discovered in
place, and the root `.claude-plugin/marketplace.json` points its single
entry at `./skills`. External catalogs can reference the plugin with a
`git-subdir` source (`path: "skills"`), which sparse-clones only that
directory instead of the whole repo.

`claude plugin validate` passes on both manifests. `claude --plugin-dir
./skills` discovers all four skills
(`nextjs:next-cache-components-adoption`,
`nextjs:next-cache-components-optimizer`, `nextjs:next-dev-loop`,
`nextjs:next-partial-prefetching-adoption`).
2026-07-17 19:46:13 +00:00
Sebastian "Sebbie" SilbermannandGitHub f8dc962e17 [ci] Avoid apt-get in the next-stats-action Docker image (#95847)
The `Stats (webpack)` / `Stats (turbopack)` CI jobs have been
intermittently failing on PRs and canary (e.g. [this
run](https://github.com/vercel/next.js/actions/runs/29476089144/job/87563318723)).
The jobs run on arm64 runners, where the `ubuntu:24.04` base image
fetches apt packages from `ports.ubuntu.com`, which is intermittently
unreachable. Since `apt-get update` only warns when index fetches fail,
the Docker build breaks one layer later at `apt-get install` with
"Unable to locate package curl".

This change switches the base image to `buildpack-deps:noble-scm`, which
already ships curl, ca-certificates, and git, so the build no longer
makes any apt calls at all. The `apt-get upgrade` step is dropped along
with it; it was already a silent no-op whenever the mirror was down, and
the ephemeral CI container does not rely on it.

Both `.github/next-stats-action.Dockerfile` (the one CI builds via
`action.yml`) and the duplicate
`.github/actions/next-stats-action/Dockerfile` are updated to stay in
sync.
2026-07-17 10:45:36 -07:00
583ce21786 Back/forward set the Nav Inspector back to pending (#95865)
A back/forward (history traversal) navigation should not be captured by
the Nav Inspector, because it's not the same as a regular navigation: it
reads the entire navigation from cache, rather than fetching new data.
It might be the case that data in the bfcache is missing for some
reason, but in the normal case all the data will be available and the
navigation will be instant. So that's how we should model it in the Nav
Inspector.

In the future we may want to update the Nav Inspector UI to show that
the current screen was the result of a back/forward navigation, but for
now we will just reset the Nav Inspector back to the pending ("Waiting
for navigation...") state.

Includes the regression tests from #95793.

Co-authored-by: Dan Abramov <[email protected]>
2026-07-17 11:44:05 -04:00
Aurora ScharffandGitHub 8a06e9e384 fix(agent-rules): pad managed AGENTS.md block with blank lines (#95892)
### What

The generated `nextjs-agent-rules` block in `AGENTS.md` glued the `<!--
BEGIN:nextjs-agent-rules -->` / `<!-- END:nextjs-agent-rules -->`
comment markers directly against the `#` heading and the surrounding
paragraphs:

```md
<!-- BEGIN:nextjs-agent-rules -->
# This is NOT the Next.js you know
...
<!-- END:nextjs-agent-rules -->
```

Markdown formatters (Prettier, and CommonMark tooling in general) treat
block-level HTML comments as needing surrounding blank lines, so
formatting an `AGENTS.md` reflows the block:

```md
<!-- BEGIN:nextjs-agent-rules -->

# This is NOT the Next.js you know
...

<!-- END:nextjs-agent-rules -->
```

On the next `next dev`, the generator detects the block as non-current
and rewrites it back to the glued form. For any project that runs
Prettier over `AGENTS.md`, this produces churn on every commit — the
opposite of what the block's own "commit it to keep the tree clean" note
promises.

### Change

Emit blank lines around the markers so the generated block is
formatter-stable. Both generators are updated together:

- `packages/next/src/server/lib/generate-agent-files.ts` (`next dev`
writer)
- `packages/create-next-app/helpers/generate-agent-files.ts`

The `next-codemod` `agents-md` refresh delegates to the installed
package's generator, so it needs no change. The docs sample in
`ai-agents.mdx` and this repo's own `packages/next/AGENTS.md` already
use the blank-line shape, so they now match what's generated.

### Notes

- Existing projects get a one-time block rewrite on their next `next
dev` (expected — the block is described as re-added by `next dev`),
after which it stays stable under formatting.
- The `agent-rules-auto-generate` test asserts against the live
generator output, so it tracks the new shape automatically.
2026-07-17 14:15:52 +02:00
danandGitHub e75d082512 Revert "Run more test suites under cacheComponents flag" (#95884)
Reverts vercel/next.js#95878

Don't understand the failure after merging into canary yet, let's revert
to unblock CI
2026-07-17 00:33:26 +00:00
4395d7c807 Fix repeated navigations while the Instant Navigation lock is held (#95864)
With the Instant Navigation Testing lock held (the Navigation Inspector
paused), repeated client navigations between pages that share a layout
could sometimes get stuck without ever resolving.

The root cause turned out to be a subtle problem with the client
router's use of `useDeferredValue` to switch between the cached UI and
the final UI. The mechanism only works as we intend when mounting a new
part of the tree. When updating an existing part of the tree, like a
shared layout, React will skip the cached UI entirely.

We were already aware of this issue with the `useDeferredValue`
approach. The plan is to instead model cached navigation as an
optimistic update followed by a transition update. Before we can make
such a change, though, we need to make a change in React to allow
optimistic updates to suspend (currently, optimistic updates act like
sync updates, and can trigger existing Suspense boundaries to switch
back to their fallback state).

To workaround this issue when using the Navigation Inspector, we're
going to change how the inspector works when multiple navigations are
performed during the same "lock". Instead of keeping the entire sequence
blocked until the end, we will instead only block the most recent one.
This more closely matches what the inspector UI implies, anyway: it
doesn't show a stack of pending navigations, only the most recent one.

This doesn't absolve us from needing to switch to using an optimistic
update. That's needed regardless to address similar behavior in
production. But this sidesteps the issue for now, and we were planning
to make this change to the Navigation Inspector regardless.

Co-authored-by: Sam Selikoff <[email protected]>
2026-07-16 20:19:57 -04:00
next-js-bot[bot]andGitHub 68033b385a v16.3.0-canary.88 v16.3.0-canary.88 2026-07-16 23:32:58 +00:00
danandGitHub 6e558b1790 Run more test suites under cacheComponents flag (#95878)
Similar to https://github.com/vercel/next.js/pull/95877.

Some of these need loading boundaries so that CC doesn't complain about
being blocking.
2026-07-16 22:53:53 +01:00
Andrew ClarkandGitHub bc48ef76ee Unify appShells flag with Partial Prefetching (#95415)
The experimental `appShells` flag was added while the feature was being
developed. It was not meant to be a public-facing flag.

Some of the behavior that was gated behind the `appShells` flag is
purely an optimization and can be landed without any gate.

There are also some behaviors that we don't want to turn on unless
you've opted into the new prefetching model via Partial Prefetching.
Arguably these too are internal optimizations, but because they can
change the number of requests that are made to the server (e.g. one
request for the shell, another for the page data), we will gate these
behind Partial Prefetching to minimize the impact on existing
applications.

The result is that until you opt into Partial Prefetching, you should
not see any meaningfully detrimental impact to prefetching costs,
regardless of how your app is structured.
2026-07-16 16:30:57 -04:00
Tim NeutkensandGitHub 491f78099c Fix Request Insights span collection (#95818)
## Summary

Fix Request Insights collection so the dev server records all non-hidden
Next.js spans locally, including non-vanilla trace and wrapped spans,
while preserving the existing OpenTelemetry export allowlist unless
verbose tracing is enabled.

Keep reporting timelines correct by propagating request identity before
work async storage exists, honoring explicit span timestamps, and
anchoring request duration to the BaseServer request span. Standardize
span categories on `next.span_category`, retain presentation-only UI
filtering, and filter internal request identity headers at ingress.

## Verification

- `pnpm test-dev-turbo
test/development/app-dir/request-insights/request-insights.test.ts`

<!-- NEXT_JS_LLM -->
2026-07-16 14:24:43 +02:00
danandGitHub 3baea3576e Revert "Replay same-document traversals that happen before hydration" (#95853)
Reverts vercel/next.js#95682

This breaks CC (https://github.com/vercel/next.js/issues/95848) due to
PPR codepath doing something different. Although Claude says
https://github.com/vercel/next.js/commit/da4d63d759a9bffd3e8c586bac1e4dabffd5b35d
can work around it, I think it's safest to revert this given that I
don't know what the right full fix is.

I also think we need more test coverage because the navigation test
suite is off in CC mode.

I'll send a follow-up with all the failing tests we know of (from #95682
and new) so we can fix this for good after a closer look.
2026-07-16 12:19:57 +00:00
Sebastian "Sebbie" SilbermannandGitHub 3ae5630d0a [ci] Allow running all deploy tests with builds from a private registry (#95784) 2026-07-16 11:33:21 +02:00
Sam PoderandGitHub 153bf8ac5f [turbopack] Only ship pages-router routes in the client chunk-group bootstrap manifest (#94671)
This is a small performance thing Claude pointed out that I've added:

```
// Only the pages-router `route-loader` reads `__TURBOPACK_PAGE_BOOTSTRAP`. App routes
      // navigate via flight and never use it, so skip app entries to keep `_buildManifest.js`
      // (loaded on every page) small.
```
2026-07-16 00:35:23 -07:00
Sam PoderandGitHub f282e478b4 [turbopack] Inline the chunk group bootstrap in Next.js to drop the per-route runtime (#94666)
This PR builds on top of the other PRs in this stack, it is the PR that
switches to inlining the bootstrap code and dropping the runtime file
that each route had.
2026-07-16 00:35:23 -07:00
Sam PoderandGitHub b2e7c8bed0 [turbopack] Add chunk_group_bootstrap_params and the chunk-loading global to the build manifest (#94663)
This PR inserts the bootstrapping parameters into the build manifest so
they can then be inlined in
https://github.com/vercel/next.js/pull/94666.
2026-07-16 00:35:22 -07:00
Sam PoderandGitHub 856765a176 [turbopack] Add registerEntry() to handle inline bootstrapping (#94664)
In https://github.com/vercel/next.js/pull/94631, we started pushing
items to `globalThis["TURBOPACK"]` that were of a slightly different
shape. See the comment on
https://github.com/vercel/next.js/pull/94631#issue-4626372740.

This PR adds a new method `registerEntry()` that is able to take that
new shape (the object without the file name as an argument) and still
instantiate the module + load the other chunks.
2026-07-16 00:35:22 -07:00
Sam PoderandGitHub 6d9e6f0533 [turbopack] Add inline_chunk_group_bootstrap to BrowserChunkingContext and chunk_group_bootstrap_params to ChunkGroupResult (#94661)
We used to generate the runtime file for each `ChunkGroupResult` in
`evaluated_chunk_group()`, I've added `chunk_group_bootstrap_params`
which are the parameters that were unique to each chunk group. These are
inlined into each page's HTML in
https://github.com/vercel/next.js/pull/94666. They look like:

```javascript
{"otherChunks":["output/0_9x_turbopack-tests_tests_snapshot_basic-tree-shake_export-namespace_input_1mqgz2-._.js"],
"runtimeModuleIds":["[project]/turbopack/crates/turbopack-tests/tests/snapshot/basic-tree-shake/export-namespace/input/index.js [test] (ecmascript)"]}
```

Whether or not the inline-able code is generated is based on the
`inline_chunk_group_bootstrap` which is still false in all cases at the
moment but will be turned to true in
https://github.com/vercel/next.js/pull/94666.
2026-07-16 00:35:21 -07:00
Sam PoderandGitHub 6faa5536bf [turbopack] Create a chunk_group_bootstrap_params() function (#94631)
This method generates the params for this code (random example for
reference):

```javascript
(globalThis["TURBOPACK"] || (globalThis["TURBOPACK"] = [])).push([
    "output/1ece_tests_snapshot_basic-tree-shake_export-namespace_input_index_0tbr8qy.js",
    {"otherChunks":["output/0_9x_turbopack-tests_tests_snapshot_basic-tree-shake_export-namespace_input_1mqgz2-._.js"],"runtimeModuleIds":["[project]/turbopack/crates/turbopack-tests/tests/snapshot/basic-tree-shake/export-namespace/input/index.js [test] (ecmascript)"]}
]);
```
This is a pretty small change on its own (no functionality change), it
makes it a separate method so that it can be called in future PRs. I
will flag that the shape for inline-d bootstrap code will be slightly
different (further up the stack). Because it isn't a chunk itself it
does not have the first item in the array
(`output/1ece_tests_snapshot_basic-tree-shake_export-namespace_input_index_0tbr8qy.js`):

```javascript
(globalThis["TURBOPACK"] || (globalThis["TURBOPACK"] = [])).push({"otherChunks":["static/chunks/node_modules_react-dom_82bf80._.js","static/chunks/_4f9bce._.js","static/chunks/pages_index_tsx_5a9e._.js"],"runtimeModuleIds":[96168]});
```

This item only has `otherChunks` and `runtimeModuleIds`. New code is
added in https://github.com/vercel/next.js/pull/94664 to handle this
different shape.
2026-07-16 00:35:21 -07:00
Sam PoderGitHubBenjamin Woodruffvercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
8aefb1c71a [turbopack] Create a shared asset with browser runtime code (#94586)
The goal of this PR is to extract all the generic runtime code into one
asset that is shared by each route. This makes the per-route runtime
tiny, which will be removed in later PRs in this stack.

The diff is unfortunately massive, however, these are almost all because
of the snapshots.

---------

Co-authored-by: Benjamin Woodruff <[email protected]>
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
2026-07-16 00:35:20 -07:00
danandGitHub b7ab553862 Turbopack: trace externals imported only by server actions (#95824)
#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
https://github.com/vercel/next.js/discussions/95130#discussioncomment-17652155.

---

<details>

## Summary

Fixes the NFT tracing regression behind #95815 and the deploy failures
reported in
https://github.com/vercel/next.js/issues/87737#issuecomment-4897366831.

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 `[email protected]` 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>
2026-07-16 07:13:26 +02:00
next-js-bot[bot]andGitHub 50925bb80a v16.3.0-canary.87 v16.3.0-canary.87 2026-07-15 23:34:23 +00:00
Sam PoderandGitHub b7e3285893 [turbopack] Generate component chunks for each merged group to increase cache hits (#95261)
This is a WIP PR to attempt to achieve this:

<img width="653" height="291" alt="Screenshot 2026-06-28 at 11 53 17 pm"
src="https://github.com/user-attachments/assets/68a78003-b76c-40e2-bbea-ca581f468eef"
/>

This does involve emitting extra chunks, though in theory, they are
already being emitted.

I'm reusing the `module_chunks` field on `OutputChunkRuntimeInfo`:

```rust
/// List of paths of chunks containing individual modules that are part of
/// this chunk. This is useful for selectively loading modules from a chunk
/// without loading the whole chunk.
pub module_chunks: Option<ResolvedVc<OutputAssets>>,
```

This does cause larger build sizes:

| App | Client chunk files (baseline → PR) | Difference | Client chunk
bytes (baseline → PR) | Difference |
| --- | ---: | ---: | ---: | ---: |
| vercel-site | 3651 → 5245 | +1594 (43.7%) | 344.5 MiB → 418.4 MiB |
+73.9 MiB (21.5%) |
| vercel-marketing | 2242 → 2634 | +392 (17.5%) | 163.5 MiB → 180.7 MiB
| +17.2 MiB (10.5%) |
| **Total** | **5893 → 7879** | **+1986 (33.7%)** | **508.0 MiB → 599.1
MiB** | **+91.1 MiB (17.9%)** |
2026-07-15 15:57:11 -07:00
Josh StoryandGitHub 83e99f0a2e Exclude stale under 5 minutes from app shells (#95833)
App Shells are meant to be useful for handling navigations that are not
prefetched. If the stale time is very low then they must be evicted
often from the client router and thus their utility is undermined. We
now exclude caches that have a stale time under 5 minutes from app
shells.

For the default cacheLife profiles this means only the `seconds` profile
is excluded becasue every other profile has a stale of exactly 5 minutes
at this time.

In the future we may want to allow for this threshhold to be configured.
This shouldn't be too disruptive since generally content that is
changing often is likely not in your app shell to begin with.
2026-07-15 14:43:48 -07:00
Tim NeutkensandGitHub 22fa026c34 docs: remove experimental @next/routing note (#94903)
### What?

Remove outdated experimental status notices for `@next/routing` from the
adapters documentation and package README.

### Why?

`@next/routing` is no longer experimental, and the existing notices
incorrectly tie its stabilization to the adapters API.

### How?

Delete the obsolete notices while leaving the routing API documentation
unchanged.

### Verification

- `pnpm prettier --with-node-modules --ignore-path .prettierignore
--write
docs/01-app/03-api-reference/07-adapters/05-routing-with-next-routing.mdx
packages/next-routing/README.md`
- Repository lint-staged checks passed during commit
- Not run: runtime tests (documentation-only change)

<!-- NEXT_JS_LLM_PR -->
2026-07-15 22:10:32 +02:00
Sam PoderandGitHub 98c9754ad8 [turbopack] Tell agents not to mention next.config.js options (#95825)
Common piece of feedback I've gotten on my PRs. Would be nice to have it
in the `AGENTS.md` as I often use Claude to one shot the plumbing of a
flag.

though - maybe we should have a turbopack-specific AGENTS.md?
2026-07-15 11:57:45 -07:00
Niklas MischkulnigandGitHub 1a7e6bda0f chore: Remove stale build warning (#95813)
Added in https://github.com/vercel/next.js/pull/88001
But it doesn't actually work. It thinks the build is always stale
2026-07-15 18:40:46 +00:00
danandGitHub 2ce362f312 Replay same-document traversals that happen before hydration (#95682)
Fixes a race you can observe if you:

1. Open page A
2. Navigate to page B
3. Cmd+Shift+R while on page B...
4. ...and then navigate Back super fast

In that situation, the router gets confused and shows page B's content
with page A's URL. From then on, going Back and Forward changes the URL
(and tab title) but keeps showing B's content. See the new tests.

## Why This Happens

Navigating from A to B client-side creates B's history entry via
`pushState`. Reloading B replaces that document with B's fresh
server-rendered HTML. Pressing Back at that point fires `popstate` to A,
but nothing listens to it yet. Then JS loads, and we happily hydrate B's
content onto B's HTML despite technically being on A route.

## The Fix

Use Navigation API to detect that we’re on a different entry than we
started. Once the router mounts, replay the missed traversal the same
way the `onPopState` handler would have handled it.

(I originally tried to avoid using Navigation API but wasn’t sure how to
detect this reliably.)

## Test Plan

New tests are red before the fix.
2026-07-15 18:35:15 +01:00
JosephGitHubTobias Koppersvercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
7696b6a821 docs: cssChunking graph option (#95693)
Docs for the newly added `graph` option, with this additional section,
`Balancing requests and grouping`, trying to explain how the graph
option works.

Also adding a couple new sections:

- Choosing a strategy
- Debugging what a route actually uses
- Example
- ends with a deep dive on the high level idea of the graph alg, trying
to explain more of `weightDistribution`

Closes; https://linear.app/vercel/issue/DOC-6481/csschunking-graph-mode
and to some degree
https://linear.app/vercel/issue/DOC-3447/document-how-the-css-chunking-algorithm-works

---------

Co-authored-by: Tobias Koppers <[email protected]>
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
2026-07-15 17:47:40 +02:00
0156307f55 [Bench] Extend bench app to have realistic client chunk counts (#95814)
Follow-up to https://github.com/vercel/next.js/pull/95807.

Makes payload size match prod sizes closer and aligns chunk count by
adding a lot of client modules.

I originally thought to unify them into `client.js` or such but maybe
it's good to see how compilation behaves with many small files? Which is
how real projects do that.

```
=== dashboard.html (fixture)  vs  p-overview.html (real)
  total KB                            665          637
  rows (model/I/T/other)      258/111/3/1 240/125/5/27
  byte share model/I/T %          43/57/0      36/62/2
  median row size B                   906          106
  max depth                            43           53
  mean depth                          8.9         10.5
  elements per KB(model)              7.7          5.2
  pure-data byte share %               18           21
  client-ref elements %                35           32
  objects:elements ratio             1.18         1.23
  avg props per element               2.6          3.1
  median children fanout                4            4
  string bytes %                       50           54
  median string len B                  12           15
  row refs per KB                     0.4          0.4
  encoded scalars per KB              0.7          1.2
  undefined markers                   247          740

=== docs.html (fixture)  vs  nextjs-docs.html (real)
  total KB                            487          487
  rows (model/I/T/other)        72/40/7/1   55/43/2/20
  byte share model/I/T %           89/8/3       94/6/0
  median row size B                   199          340
  max depth                            27           32
  mean depth                         22.3         12.3
  elements per KB(model)              0.6          0.8
  pure-data byte share %                7            9
  client-ref elements %                29           33
  objects:elements ratio             8.67         4.92
  avg props per element               2.0          2.8
  median children fanout                3            4
  string bytes %                       47           64
  median string len B                  17           35
  row refs per KB                     0.2          0.1
  encoded scalars per KB              7.4          2.9
  undefined markers                  3586         1377

=== blog.html (fixture)  vs  vercel-blog.html (real)
  total KB                            778          797
  rows (model/I/T/other)        72/39/0/1  102/53/7/14
  byte share model/I/T %           93/7/0       87/8/5
  median row size B                   145          505
  max depth                            34           44
  mean depth                          9.6         12.2
  elements per KB(model)              0.7          1.1
  pure-data byte share %               92           85
  client-ref elements %                38           33
  objects:elements ratio            31.19        16.39
  avg props per element               1.9          2.7
  median children fanout                3            4
  string bytes %                       46           48
  median string len B                   6            9
  row refs per KB                     0.1          0.1
  encoded scalars per KB              0.4          0.6
  undefined markers                   242          426
```

Co-authored-by: Claude Fable 5 <[email protected]>
2026-07-15 15:13:35 +02:00
7ffacec8ef Add more realistic bench fixtures (#95807)
This adds more fixtures modeled after Flight payloads from real sites:

- Vercel Dashboard-like (very app-y)
- React Docs-like after App Router conversion (mostly MDX site)
- Vercel Blog-like (passing down data from CMS)

(Actual data is randomly generated with a seed)

These are simplifications but I tried to incorporate the originals'
corresponding quirks. Such as Vercel Dashboard having many client
components; syntax highlight with many small spans in React Docs; Vercel
Blog currently shipping a load of data unnecessarily on the index page.
(The last one is not ideal but I think we should actually benchmark
"bad" cases like this too so I kept that.)


### Screenshots

<img width="1325" height="1021" alt="Screenshot 2026-07-15 at 04 29 43"
src="https://github.com/user-attachments/assets/62c80722-6fd5-4884-89db-106345f6412d"
/>

<img width="1360" height="994" alt="Screenshot 2026-07-15 at 04 30 21"
src="https://github.com/user-attachments/assets/0db93cd8-43ca-41df-b3e2-c422e0c94656"
/>

<img width="1368" height="991" alt="Screenshot 2026-07-15 at 04 30 43"
src="https://github.com/user-attachments/assets/9369e9be-12a4-4a1e-af32-01b6fdd4a457"
/>


### Comparison with real payloads

```
=== dashboard.html (fixture)  vs  p-overview.html (real)
  total KB                            208          637
  rows (model/I/T/other)       186/48/7/1 240/125/5/27
  byte share model/I/T %           92/4/4      36/62/2
  median row size B                   590          106
  max depth                            28           53
  mean depth                          8.4         10.5
  elements per KB(model)             14.9          5.2
  pure-data byte share %               24           21
  client-ref elements %                41           32
  objects:elements ratio             1.17         1.23
  avg props per element               1.7          3.1
  median children fanout                4            4
  string bytes %                       24           54
  median string len B                  10           15
  row refs per KB                     0.9          0.4
  encoded scalars per KB              3.5          1.2
  undefined markers                   347          740

=== docs.html (fixture)  vs  nextjs-docs.html (real)
  total KB                            261          487
  rows (model/I/T/other)        58/15/7/1   55/43/2/20
  byte share model/I/T %           93/1/6       94/6/0
  median row size B                   193          340
  max depth                            27           32
  mean depth                         21.9         12.3
  elements per KB(model)              0.8          0.8
  pure-data byte share %                8            9
  client-ref elements %                16           33
  objects:elements ratio             6.26         4.92
  avg props per element               1.7          2.8
  median children fanout                4            4
  string bytes %                       47           64
  median string len B                  17           35
  row refs per KB                     0.2          0.1
  encoded scalars per KB              7.5          2.9
  undefined markers                  1949         1377

=== blog.html (fixture)  vs  vercel-blog.html (real)
  total KB                            475          797
  rows (model/I/T/other)        41/15/0/1  102/53/7/14
  byte share model/I/T %          100/0/0       87/8/5
  median row size B                   426          505
  max depth                            34           44
  mean depth                          9.7         12.2
  elements per KB(model)              0.8          1.1
  pure-data byte share %               92           85
  client-ref elements %                23           33
  objects:elements ratio            28.92        16.39
  avg props per element               1.9          2.7
  median children fanout                3            4
  string bytes %                       46           48
  median string len B                   6            9
  row refs per KB                     0.1          0.1
  encoded scalars per KB              0.4          0.6
  undefined markers                   161          426
```

---------

Co-authored-by: Claude Fable 5 <[email protected]>
2026-07-15 13:46:22 +02:00
Tim NeutkensandGitHub 1d52ffaf1b Fix Request Insights subscription initialization (#95794)
## Summary

Pass the configured Request Insights state into the dev bundler service
so it subscribes to insight updates during initialization. The service
is constructed outside request-local tracing state, so checking only
`isRequestInsightsEnabled()` can incorrectly skip the subscription even
when Request Insights is enabled in configuration.

## Verification

- `pnpm build-all`
- `pnpm prettier --with-node-modules --ignore-path .prettierignore
--write packages/next/src/server/lib/dev-bundler-service.ts
packages/next/src/server/lib/router-server.ts`
- `npx eslint --config eslint.config.mjs --fix
packages/next/src/server/lib/dev-bundler-service.ts
packages/next/src/server/lib/router-server.ts`

<!-- NEXT_JS_LLM -->
2026-07-15 10:55:33 +00:00
danandGitHub d87f2bd2be Model async userland loading in app routes as a state machine (#95791)
Extracted from https://github.com/vercel/next.js/pull/95468, tries to
address @lubieowoce feedback.

This should be a pure refactor with no publicly observable behavior
changes. We want to simplify the state of how we're loading and tracking
modules, and simplify signatures:

- Extract a state machine into `LazyModule` that hides per-module state.
You can kick it (`loadIfNeeded`), wait for completion with
`waitUntilLoaded`, or peek-or-throw with `assertLoaded`.
- Reading `.userland` while pending now throws with an invariant so we
don't do it accidentally again. Should be unreachable from current
callsites.
- Remove the non-thunk overload from `userland` factory.

Added tests to cover the cases that the refactor had a risk of breaking.
2026-07-15 10:49:07 +01:00
danandGitHub 40b0e3d848 Preserve init errors from async route modules (#95799)
Extracted from https://github.com/vercel/next.js/pull/95468.

We did not have error handling around async module initialization. As a
result, in `output: 'export'` mode, an error during async initialization
were reported as unhandled rejections. Now it properly fails the build.
2026-07-15 10:49:06 +01:00