34980 Commits
Author SHA1 Message Date
zandGitHub 559bbc961a Delete upstream workflows
This fork does not ship upstream's releases, and its hosted-runner jobs
never start here.

Claude-Session: https://claude.ai/code/session_01HuMDfgFssPUptYUzgZ6Cp8
2026-09-24 10:00:38 -07:00
zeekayandHanzo Dev 5bc0eaaba7 ci: canonical pair — hanzo.yml + forge caller
github.com has no runner for hanzo-build-linux-amd64, so a caller under
.github/workflows is a gate that can never be scheduled. This is the ~7-line
caller on the plane that can (git.hanzo.ai git-runner fleet), pinned @v1.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-06 02:42:16 -07:00
next-js-bot[bot]andGitHub f3edea1b06 v16.3.0-canary.103 v16.3.0-canary.103 2026-07-29 23:35:42 +00:00
a5d7c97d17 Update PWA guide with enhanced offline support details and example links for serwist (#96360)
Updates the Progressive Web Apps guide’s Offline Support section to
point the primary Serwist + Next.js example at
[`next-turbo-basic`](https://github.com/serwist/serwist/tree/main/examples/next-turbo-basic)
(Turbopack), and keeps a note linking the webpack-based
[`next-basic`](https://github.com/serwist/serwist/tree/main/examples/next-basic)
example.

<!-- Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that
you follow the checklist sections below.
Choose the right checklist for the change(s) that you're making:

## For Contributors

We encourage you to use AI to assist you in researching, creating, and
reviewing changes. However, you must review and deeply understand the
contributions you are making. For this reason, **pull request
descriptions from external contributors must be written by a human**.

### Improving Documentation

- Run `pnpm prettier-fix` to fix formatting issues before opening the
PR.
- Read the Docs Contribution Guide to ensure your contribution follows
the docs guidelines:
https://nextjs.org/docs/community/contribution-guide

### Fixing a bug

- Related issues linked using `fixes #number`
- Tests added. See:
https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md

### Adding a feature

- Implements an existing feature request or RFC. Make sure the feature
request has been accepted for implementation before opening a PR. (A
discussion must be opened, see
https://github.com/vercel/next.js/discussions/new?category=ideas)
- Related issues/discussions are linked using `fixes #number`
- e2e tests added
(https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs)
- Documentation added
- Telemetry added. In case of a feature if it's used or not.
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md

### Signed commits

- This repository requires verified commit signatures on protected
branches.
- If this pull request is blocked for unsigned commits, re-sign the
commits and force-push the branch.
- A `Signed-off-by` line in the commit message is not enough.

## For Maintainers

- Minimal description (aim for explaining to someone not on the team to
understand the PR)
- When linking to a Slack thread, you might want to share details of the
conclusion
- Link both the Linear (Fixes NEXT-xxx) and the GitHub issues
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

Updates the Progressive Web Apps guide’s Offline Support section to
point the primary Serwist + Next.js example at `next-turbo-basic`
(Turbopack), and keeps a note linking the webpack-based `next-basic`
example.

### Why?

Turbopack is the default bundler, so the main docs link should match
that setup. Webpack users still need a clear path to the older example
without treating webpack as the default.

### How?

In `docs/01-app/02-guides/progressive-web-apps.mdx`, changed the Serwist
docs link from `examples/next-basic` to `examples/next-turbo-basic`, and
rewrote the note to link `examples/next-basic` for webpack.

Closes NEXT-
Fixes #

-->

---------

Co-authored-by: Joseph <[email protected]>
2026-07-29 19:23:07 -04:00
JosephandGitHub b59fae0429 [fragment-scroll] Stop blurring on navigations (#96113)
Dynamic pages (all pages in dev), blur and select the body as
`activeElement`.

- [x] e2e for https://github.com/vercel/next.js/issues/96050
- [ ] attempt a fix that prevents blur
2026-07-29 19:13:35 -04:00
67f16a522d Fix PPR rendering for configured HTML bots (#96364)
## Summary

When PPR is enabled, requests matching a custom `htmlLimitedBots`
pattern could still use the prerendered route path. As a result, the
configured blocking-metadata behavior was not applied consistently.

Use the existing streaming-metadata decision when selecting the PPR
render path. Built-in bots retain their existing fully buffered
behavior, custom HTML-limited bots can continue streaming body content
after metadata resolves, and regular user agents remain unchanged.

## Verification

- HEADLESS=true pnpm test-start-turbo
test/e2e/app-dir/html-limited-bots-ppr/html-limited-bots-ppr.test.ts
- HEADLESS=true pnpm test-start-webpack
test/e2e/app-dir/html-limited-bots-ppr/html-limited-bots-ppr.test.ts

Co-authored-by: Sebastian Silbermann <[email protected]>
2026-07-29 15:49:57 -07:00
JosephandGitHub 5cdcbbb05b Bump postcss to 8.5.23 (#96107)
Note that https://github.com/advisories/GHSA-6g55-p6wh-862q does not
affect Next.js users unless they build from untrusted source code (which
would have more severe security implications). We're merging this to
reduce noise from security scanners.

- 8.5.21 is 50h+ old so it can be installed
- 8.5.22 is still under 48h - valid at 2026-07-24 08:48:15 UTC 

Closes: https://github.com/vercel/next.js/issues/96349
2026-07-29 18:22:56 -04:00
4286e5ff35 Ensure unique resolved headers() value between render passes (#96085)
A HTTP request can render the same React tree in multiple passes with
different semantics for `connection()`: the prospective and final
prerenders of a runtime prefetch, or a navigation's dynamic render and
the runtime prerender that is spawned from it to refresh the client's
prefetch cache. All of these passes previously resolved `headers()` to
the single sealed headers object created lazily by the request store, so
userland caches keyed on the identity of `await headers()` (any
per-request memoization that treats the headers object as "the request")
leaked promises across passes.

With this change, every render pass resolves `headers()` to a distinct
object over the same underlying data, making "the headers object
identifies the request within one render pass" a real contract.


---------

Co-authored-by: Claude Fable 5 <[email protected]>
2026-07-29 18:16:34 -04:00
Will Binns-SmithandGitHub 6fc7bf8af1 Share Ecmascript HMR chunk versioning, diffing, and merging between browser and node (#96325)
## Summary

`turbopack-nodejs` and `turbopack-browser` each carried their own copy
of the Ecmascript chunk versioning and HMR diffing stack.
`chunk_list/merged_update.rs` already documented the intent to share
this, noting the turbo-tasks value types "cannot be generic and
therefore remain per-runtime". A `value_trait` resolves that: the shared
machinery is written against `EcmascriptHmrChunkContent`, which each
runtime implements in a few lines to expose `entries()` and
`own_version()`.

The shared code now lives in `turbopack-ecmascript/src/hmr/`
(`version.rs`, `update.rs`, `content.rs`, `merger.rs`). Both runtimes'
`ecmascript/version.rs`, `ecmascript/update.rs`, and
`ecmascript/**/merged/` directories are deleted.

No struct fields were widened and no `ChunkingContext` methods changed.

### Behavior changes

- Browser chunk version IDs now hash `minify_type`, matching node. IDs
are opaque and recomputed in-memory on both ends of an HMR connection,
so this cannot desync a client.
- The shared diff uses node's lazy `entries()` materialization, so
chunks with only deletions no longer materialize any `Vc<Code>`. This
now applies to the browser path too.
- Node error text said "chunk path ... is not in client root", a
copy-paste artifact. Now says "output root".
- `#[turbo_tasks(trace_ignore)]` is applied consistently to the merged
chunk version; previously only the browser copy had it.

Browser chunk content keeps the default `VersionedContent::update`.
Overriding it bypasses the `ChunkListUpdate` envelope the client runtime
expects.

### Not included

Unifying the chunk-content structs. That requires widening to `Box<dyn
ChunkingContext>`, and both chunking contexts define `minify_type` twice
— an inherent method and a `ChunkingContext` method whose trait default
is `NoMinify` — so it needs separate verification. The trait added here
lets the two structs coexist at no cost.

The runtime, evaluate, and entry chunk types are also out of scope:
`get_browser_runtime_code` takes eight more parameters than
`get_node_runtime_code`, so those differ behaviorally rather than by
duplication.

<!-- NEXT_JS_LLM -->
2026-07-29 14:51:33 -07:00
be1424f3dc Make retry stop when the time it was given is up (#96354)
How long do you expect this to wait at worst (before failing)?

```js
await retry(async () => {
  expect(await browser.elementById('never-appears').text()).toBe('x')
}, 15_000)
```

After this PR, the answer is 15 seconds. (Well, technically, 15 seconds
+ whatever last attempt is, so 20.)

But before this PR, the answer was 3 minutes.

## What?

There's a bug (IMO) in `retry`. Instead of waiting for the time you give
it, it counts tries.

For example, `retry(fn, 15_000)` reads as "keep trying for 15 seconds".
However, what it actually was doing is divide 15000 by the 500ms
interval and try 30 times, sleeping 500ms in between every try.

This is a problem because **it wasn't measuring the stall time of each
try itself.**

When a try is cheap, it doesn't matter. But a try that looks for an
element in the browser isn't cheap: if the element isn't there, the
selector waits 5 seconds before giving up.

In the example above, each try sits in the selector for its full 5
seconds, and there are 31 of these intervals, plus the 15 seconds of
sleeping in between. This ends up waiting 170103ms, i.e. three minutes
for a wait that says 15 seconds.

Jest kills the test at its own timeout long before that, and the actual
error gets thrown away. What's left is `Exceeded timeout of 120000 ms`,
which doesn't say which assertion never came true. In the one I measured
it was `page.waitForSelector: Timeout 5000ms exceeded`. My agent lost an
hour trying to make sense of this twice now.

## Fix

We count time now. After the fix, the retry watches the clock and stops
when its time is up. It still always makes at least one try. The
interval no longer has to divide the duration, because nothing counts
steps any more. If the last try is slow, we're gonna wait for that last
try to end (so the timeout is still not *strictly* respected) so that we
can show the error in the correct test.

Cheap waits behave exactly as before. In my local run, a try that had to
repeat cost 251ms at the median, 459ms at the worst. So the only calls
this changes are ones that were already failing, and those now fail with
their own error instead of a test timeout. One flaky dev test that used
to die at 120 seconds with nothing to show now fails in 19.5 seconds
saying `Failed to retry within 15000ms (waited 16022ms)`, next to nine
tests that take 2.2 seconds each.

I added some regression tests. Since it's a test helper, a unit test
seemed fine.

## What this means for existing tests

The catch is that a call whose tries are slow now gets less time than it
used to, and this helper has 2110 call sites, so CI is the real check.
It found one file: the hash scroll tests in `navigation.test.ts` wait
with the default 3 seconds, and each try there costs 150-300ms on a
runner, so they were really getting about 5. They need more than 3, so
they failed on two dev shards. I gave them 10.

If this is green, we can merge it in isolation from the rest of the
stack.

---------

Co-authored-by: Claude Opus 5 <[email protected]>
2026-07-29 21:42:56 +01:00
Andrew ClarkandGitHub 3717cd3dfb Gate partial fallback shell upgrades behind partialPrefetching for next start (#96297)
In #96074 I put the `partialFallback` behavior behind the
`partialPrefetching` flag, so that we don't risk an explosion in ISR
costs for apps that haven't opted into Partial Prefetching. But it turns
out I only handled this for deploy mode — i.e. the build output consumed
by the Vercel adapter. The behavior was still unconditionally on for
`next start`.

The reason it was easy to miss is that `next start` and the adapter
express partial fallback shells through completely separate mechanisms.
The adapter emits a `partialFallback` flag into the build output and
lets the platform's ISR layer perform the shell upgrade. `next start`
has no such flag; the server performs the upgrade itself, in the
compiled page runtime. So the gate I added to the adapter output had no
effect on the self-hosted path.

To understand how the `next start` path was configured, I looked at the
PR that removed the original top-level `partialFallbacks` config flag
(#93859). Before that PR, the behavior was gated in the runtime; when
the flag was removed those gates were deleted and the behavior became
always-on.

The important subtlety is that only the *upgrade* should be gated, not
the shell machinery as a whole. On `next start`, the value that decides
whether a shell can be specialized (`remainingPrerenderableParams`) also
drives core Cache Components behavior — build-time partial prerendering
of params and serving build-time sub-shells — which must stay on
regardless of `partialPrefetching`. So this gates only the two things
that make up the "upgrade on first request" cost risk: the background
ISR revalidation that specializes a shell per request, and the
client-facing `isFallbackUpgradeable` signal that tells the client to
retry a prefetch waiting for that upgrade.

Adds coverage with a `partialPrefetching`-disabled fixture asserting
that fallback shells stay shared rather than specializing per request.
2026-07-29 19:56:49 +00:00
Aurora ScharffandGitHub d321ec8aa1 docs: modernize Next 16 upgrade AI guidance (#96314)
## What

Updates the Next.js 16 upgrade guide's AI-agent section to present:

- a recommended agent-assisted upgrade path
- a dedicated docs setup section using `npx @next/codemod@canary
agents-md`
- a copy prompt that points to the guide's own docs setup and codemod
sections, uses the Version 16 guide as the source of truth, asks the
agent to communicate tradeoffs, verify with the AI-agent runtime flow
such as `next-dev-loop` when available, and repeat the post-upgrade docs
check
- a non-agent path that keeps the existing upgrade codemod instructions

It also removes the stale external MCP setup from the upgrade flow,
calls out the async Request APIs codemod gap, and clarifies how to
migrate or remove removed `experimental.dynamicIO` /
`experimental.useCache` config.

## Why

The upgrade guide should make the docs setup useful for humans and
agents before migration starts, while keeping the agent prompt concise,
self-contained, and grounded in the docs as the source of truth.

## Checks

- `git diff --check`
- MDX fence balance check
- commit hook: `lint-staged` ran Prettier and ESLint on the changed MDX
file
2026-07-29 15:29:05 -04:00
Marcos HernanzandGitHub a80c0c0588 Cache immutable current task IDs outside the task-state lock (#96180)
## What changed

Introduce a cloneable `CurrentTaskStateHandle` that keeps the
execution's immutable `Option<TaskId>` beside the existing shared
`Arc<RwLock<CurrentTaskState>>`.

Global tasks, local tasks, detached futures, and top-level runs continue
to share the same mutable state and task-local scope. Only current-task
ID reads bypass the lock; all other state remains behind the existing
`RwLock`.

This was split from #96179 following review feedback. It is
source-independent and changes only
`turbopack/crates/turbo-tasks/src/manager.rs`.

## Why

`current_task_if_available` and `current_task` acquired a shared
standard-library `RwLock` on every native function call and tracked
read, even though the task ID is fixed for the entire execution. The
lock and its contention path remained visible in both HMR and production
profiles.

## Performance evidence

Measured at `0950e8ae05db20c33302f02257114f5b857edabc` as an incremental
change on top of the independently proposed immutable-read bypass in
#96179.

These measurements are directional evidence, not a precise standalone
estimate. Changes around 1–2% are difficult to measure reliably. The
#96179 and #96180 campaigns used separate run sets, and #96179's
absolute endpoint does not match this campaign's starting point; that
mismatch demonstrates cross-campaign noise. The percentages must not be
added, and the absolute values must not be compared across the two PRs.
The standalone GitHub aggregate benchmark also moved in the opposite
direction, reinforcing that build-level percentages are inconclusive at
this scale.

### Browser-driven HMR, 30-second B/C/C/B

- Evaluation: 19.772807 → 19.356650 ms (**-2.105%**)
- Commit: 20.632962 → 20.167726 ms (**-2.255%**)
- Both candidate runs beat both controls for both metrics.

### Production builds

- Matrix 1: **-1.804%**
- Complementary matrix 2: **-1.474%**
- Combined 24 campaigns: 1,641.839610 → 1,614.918617 ms (**-1.640%**)
- All six balanced blocks favored the candidate.
- Six-block mean: -1.636%, with 95% interval **[-2.718%, -0.555%]**.

### Causal profiles

- The `current_task_if_available` helper and contended read-lock symbols
disappeared from candidate profiles.
- HMR voluntary context switches fell 2.700%.
- Production voluntary context switches fell 2.576%.
- All eight accepted perf captures reported zero lost samples.

## Validation

On the exact standalone head
(`bce272743ff44021fda204d98924bf8519cd8c1d`):

- Complete `turbo-tasks` package tests and doctests
- Complete `turbo-tasks-backend` package tests, integrations, and
doctests
- `cargo fmt --check -p turbo-tasks -p turbo-tasks-backend`
- `cargo clippy -p turbo-tasks -p turbo-tasks-backend --all-targets --
-D warnings`
- `git diff --check`
- Conflict-free merge-tree check against current `canary` (`91c6309c52`)
2026-07-29 15:22:34 -04:00
Jimmy MillerandGitHub 39db24a48b Added cache copying support for worktrees (#95646)
This lets next detect if it is in a worktree and find the main repo and
copy turbopack caches for build or dev to make initial build faster. I
wasn't sure about commiting tests for this and how exactly we'd won't to
go about this with the git requirement. I also could do some unit tests,
but following the library conventions there wasn't a nice abstracted out
file system. So I did various tests locally. If anyone has good ideas on
what kind of testing totally opened to it.

Also left a comment that I don't look in other worktrees but instead the
root project. Not sure if this is the right answer or not. But works for
the patterns I think people typically follow.
2026-07-29 14:52:35 -04:00
JosephandGitHub 98cd1b38a8 docs(preventing-flash): cover reconciling state (#96146)
We got feedback for one case where, in dev mode, Strict Mode caused
removed the attributes added to the HTML tag by the injection script.
2026-07-29 14:05:22 -04:00
JosephandGitHub 1b92b2e943 docs: Parallel routes, conditional rendering and auth (#96351)
Closes: https://github.com/vercel/next.js/issues/71552
2026-07-29 18:01:37 +00:00
Sam PoderandGitHub fec0a517fc [turbopack] Tree shake w/ bar['foo'] syntax for star imports (#96319)
This adds tree-shaking support for this syntax:

```javascript
import * as ns from './lib';
ns["foo"]
```

Instead of expanding the usage to `All` for this one, we can restrict
ourself to just "foo".

See attached fixture.
2026-07-29 10:42:08 -07:00
Aurora ScharffandGitHub 91c6309c52 Update skills for Partial Prefetching (#96299)
## Summary

- update the Partial Prefetching adoption skill for the current runtime
prefetching model
- scope the Cache Components optimizer's runtime-prefetch limitation to
URL data
- preserve the optimizer pattern structure for URL data that cannot
move, with Partial Prefetching, targeted `<Link prefetch={true}>`, and
cached URL-data content as the requirements
- make the optimizer follow-up conditional: use targeted
`prefetch={true}` when the app already adopted Partial Prefetching,
otherwise recommend the PPF adoption skill for the broader shared App
Shell model

## Why

Andrew's Partial Prefetching work removes the old `allow-runtime`
route-config model. The skills should teach the current shape: Partial
Prefetching gives links a shared App Shell baseline with lower
duplicated prefetch cost, while `<Link prefetch={true}>` is reserved for
links where resolving URL-specific content before click is worth the
extra server work.

## Validation

- `git diff --check HEAD~1..HEAD`
- grep confirmed no `allow-runtime` / `force-runtime` references remain
in the changed Skill files
- attempted `skill-creator` quick validation, but the local Python env
is missing `yaml`
2026-07-29 11:56:31 -04:00
danandGitHub e73a25825b Restore comments dropped during a refactor (#96324)
Restores a handful of comments and TODOs in
`turbopack-core/src/source_map/utils.rs` and
`turbopack-ecmascript/src/parse.rs` that got silently dropped during the
LLM-assisted refactor in #95934, while their surrounding code stayed the
same.

Thanks @eps1lon for the tip to keep an eye on this.
2026-07-29 10:25:43 -04:00
JosephandGitHub 68cfe37506 docs: remove PPR adapter page from Pages Router (#96316)
Do not mirror PPR for Pages Router, and other adjustments.
2026-07-29 10:03:49 -04:00
Benjamin WoodruffandGitHub f6d094061e [ci] Background some steps in build_reusable to reduce setup overhead, remove unneeded lld installation (#96195)
This is a pretty minor win, but it can save a few seconds per job.


https://github.blog/changelog/2026-06-25-actions-steps-can-now-be-run-in-parallel/

Also remove the installation of `lld` for rustc with `apt-get`. It's
very slow, and rustc should already ship with `lld` these days? The
composite action to install the rust toolchain isn't run often (test
shards download a prebuilt native binary), but `build-native` it can
block other jobs from running and become a bottleneck.

Testing the full `build-and-deploy` job, which uses the rust install
action: https://github.com/vercel/next.js/actions/runs/30138483769
2026-07-28 22:49:20 -07:00
danandGitHub faa3bdf7f1 Bump @types/node to 20.17.7 to fix findSourceMap type (#96321)
Fixes
https://github.com/vercel/next.js/pull/96198#discussion_r3666434724.

Bumps the pinned `@types/node` version to `20.17.7` to get an upstream
fix for `findSourceMap` type.

Also regenerates the pnpm patch due to a conflict.

I upgraded by just a patch because I'm not sure if we rely on being on
an old version here.

## Test Plan

`findSourceMap` now shows correct types.

<img width="694" height="335" alt="Screenshot 2026-07-29 at 01 02 48"
src="https://github.com/user-attachments/assets/cfe740e0-b8bf-4edc-ac27-698f926feb32"
/>
2026-07-29 01:28:48 +01:00
next-js-bot[bot]andGitHub 0d5ff0d321 v16.3.0-canary.102 v16.3.0-canary.102 2026-07-28 23:34:15 +00:00
Sam PoderandGitHub b89bbd8277 Revert "Revert "[turbopack] Track re-exports in import_usage inside of compute_import_usage"" (#96315)
Reverts vercel/next.js#96311
2026-07-28 15:29:00 -07:00
Sam PoderandGitHub 02bbeaa84b [turbopack] Remove loader calls for dropped dynamic imports (#96284)
For modules that we were not using, that we're asynchronously loading,
we would still generate the loader but the file would not exist. This
meant building a Next.js app with:

```javascript
// pure.js — side-effect free: nothing observable happens on evaluation
export const version = '1.0.0'

// app/page.tsx
export default async function Page() {
  const {} = await import('../pure')   // ← nothing destructured out
  return <p>hello world</p>
}
```

Would error with:

```
▲ Next.js 16.3.0-canary.87 (Turbopack)
  Creating an optimized production build ...

FATAL: An unexpected Turbopack error occurred.

> Build error occurred
Error [TurbopackInternalError]: Failed to write app endpoint /page

Caused by:
- ModuleId not found for ident: [project]/pure.js [app-rsc] (ecmascript, async loader)

Debug info:
...
- Execution of PatternMapping::resolve_request failed
- ModuleId not found for ident: [project]/pure.js [app-rsc] (ecmascript, async loader)
```  

Now, we re-write those loaders to empty promises:

```diff
 async function evaluationOnly() {
-    const {} = await __turbopack_context__.A("…/pure.js [test] (ecmascript, async loader)");
+    const {} = await Promise.resolve({});
 }
 async function named() {
     const { used } = await __turbopack_context__.A("…/named.js [test] (ecmascript, async loader)");
     console.log(used);
 }
 async function pattern(locale) {
     const {} = await __turbopack_context__.f({
         "./locales/effectful.js": {
             id: ()=>"…/locales/effectful.js [test] (ecmascript, async loader)",
             module: ()=>__turbopack_context__.A("…/locales/effectful.js …")
         },
         "./locales/pure.js": {
-            id: ()=>"…/locales/pure.js [test] (ecmascript, async loader)",
-            module: ()=>__turbopack_context__.A("…/locales/pure.js …")
+            id: ()=>undefined,
+            module: ()=>Promise.resolve({})
         }
     }).import(`./locales/${locale}.js`);
 }
```

It turns `UnusedReferences` into a map between references and target
that can be dropped, where the target IDs are the unused targets. It
then passes the reference through to `pattern_mapping.rs` so it can
determine the `dropped_targets`. It needs to be target-specific as you
can have a situation (like above) where some targets are pure and some
aren't.
2026-07-28 14:37:08 -07:00
JosephandGitHub ad021e98d3 docs: add guide and references for experimental.useOffline (#93218)
Closes:
https://linear.app/vercel/issue/DOC-6390/useoffline-guide-and-api-ref

 - [x] release flag status: default / opt-out
 - [ ] publish repo and demo
- [x] ensure learning path is correct (basic -> w/ client hook -> server
actions)
2026-07-28 17:27:07 -04:00
next-js-bot[bot]andGitHub cf1e001f40 v16.3.0-canary.101 v16.3.0-canary.101 2026-07-28 20:51:42 +00:00
Will Binns-SmithandGitHub 466cdfaa27 Turbopack server hmr: avoid complete clear on graph changes (#95546)
Currently, importing a new module causes a complete eviction (`clear()`)
and re-evaluation of server chunks, both in the Turbopack runtime's
module cache and Node's `require.cache`.

Here's what happens today:

- A new module is imported into a chunk's graph
- This changes its `availability_info`, which in dev for non-entry
chunks is encoded into the chunk's filepath
- `VersionedContentMap` works entirely on chunk paths. When we construct
instructions to transition a chunk into its new state, we fail to find
the prior state and fall back to `clear()` as described above.

An ideal version of this is a refactor that implements
`VersionedContentMap` on a per-module basis, not a per-chunk one. This
PR doesn't do that, but achieves consistent module-level updates when a
chunk's availability info changes.

It does this by implementing chunk lists for server entry chunks the
same way the client hmr implementation does: an entry chunk's version
aggregates the versions of its dependent chunks (including dynamically
imported ones), keyed by merger rather than path. Entry chunks do not
encode availability info in their paths, so they are insulated from
missing versions. Updates are applied in Node.js through the same shared
merged-update machinery in the unified hmr runtime that the client
already uses, plus a new `ChunkListUpdate` branch in the server hmr
client to unwrap the merged updates.

Details:

- The merged-update wire format (`EcmascriptMergedUpdate` etc.) moves
from turbopack-browser into shared `turbopack_ecmascript::chunk_list`,
along with runtime-agnostic `ChunkListVersion` and `update_chunk_list`
implementations.
- `turbopack-nodejs` gains a chunk content merger mirroring the browser
one. `EcmascriptBuildNodeEntryChunk`'s versioned content is now a
chunk-list content over its sync and async chunks. It is version-only
and never emitted; the entry chunk still inlines its loader calls.
- The aggregate server hmr subscription now tracks only entry chunks.
Shared chunks under `server/chunks/` ride the entry's `ChunkListUpdate`
as module deltas, so their content-hash paths no longer matter.
- The Node hmr client applies `ChunkListUpdate` by feeding each nested
merged update through the shared apply path. Modules that appear in an
"added" chunk but already exist in the module cache were moved by a
chunk rename and are treated as modified.
- On a successful partial apply, the hot reloader clears the manifest
cache for updated chunks and notifies browsers to refetch RSC, without
clearing `require.cache`.

### Test Plan

Adds a series of e2e tests to catch the described manual test plan in
both entry and dynamic chunks.
2026-07-28 13:49:30 -07:00
Will Binns-SmithandGitHub b340bc7410 Turbopack HMR: extract deferring build messages and use it in server hmr (#95795)
Churn in the graph can lead to a `building` message quickly followed by
a `built` message. The underlying issue should be addressed, but for
now, extract this debounce from the client HMR implementation and use it
in server hmr.
2026-07-28 13:49:30 -07:00
8cfa551041 Turbopack: extract chunk list version/update into turbopack-ecmascript (#95661)
This moves modules out of `turbopack-browser` and into
`turbopack-ecmascript` so it can be used in the server hmr
implementation as well.

Move the chunk-list version, update, and merged-update wire types out of
`turbopack-browser` into a shared `turbopack-ecmascript::chunk_list`
module so both the browser and node chunking contexts can build on them.
Rename `EcmascriptDevChunkListVersion` to `ChunkListVersion` and make
`update_chunk_list` runtime-agnostic (plain path->`VersionedContent`
maps).

Pure refactor: no behavior change.

<!-- NEXT_JS_LLM_PR -->

---------

Co-authored-by: Claude <[email protected]>
2026-07-28 13:49:30 -07:00
Will Binns-SmithandGitHub 88155cd421 Turbopack: aggregate server HMR into one subscription (#94948)
This replaces per-chunk Server HMR turbo tasks with a single firehose
subscription that diffs every HMR chunk. This significantly cuts the
number of tokio task churn on projects with many server chunks and
centralizes the diff/clear logic. It leads to a multi-second saving in
both cold and warm builds in a large app.

This PR also renames `clear()` to `reEvaluateAllModulesExpensive()` to
label directly that this is a costly operation and should only be done
in exceptional circumstances.
    
A following PR will bring this to client chunks.
    
Rust:
- New `aggregate_hmr` module: `AggregateHmrVersion` keyed by chunk path,
`merged_partial_update` builder, and `is_hmr_eligible_chunk` (excludes
`.map` files, which would force every diff to `Total`).
- `Project::all_hmr_version_state` / `all_hmr_update` aggregate over the
whole `hmr_root_path`. The seed transition emits an empty `Partial` so
the JS consumer doesn't treat it as a restart and wipe handlers the
triggering request just populated. Any chunk requiring `Total`/`Missing`
escalates the batch.
- `VersionedContentMap::hmr_chunks_in_path` lists eligible chunks with
their `VersionedContent`.
    
NAPI:
  - `projectAllHmrEvents(target)` returns a single subscription.
    
JS:
- `setupServerHmr` subscribes once via `allHmrEvents` instead of fanning
out over `hmrChunkNamesSubscribe`.
- `reEvaluateAllModulesExpensive()` evicts every chunk under
`server/chunks/` from `require.cache` directly rather than tracking
subscriptions. This is a bit fragile as it relies on the path prefix and
scanning require.cache.
2026-07-28 13:49:29 -07:00
next-js-bot[bot]andGitHub 267d6b1a17 v16.3.0-canary.100 v16.3.0-canary.100 2026-07-28 20:42:44 +00:00
Sam PoderandGitHub dcf4607f8f Improve root detection to handle worktrees, more workspaces & stray lockfiles (#96159)
Watching too many files can hurt performance, and impacts how much work
Turbopack is doing. See for example the conversation around
https://github.com/vercel/next.js/pull/94597.

This PR handles the following four cases:

- Git worktrees: we can include a guard to prevent exiting a worktree
(by looking at the `.git` file).
- Git repository boundaries: we can include a guard to prevent us from
exiting a checked-out repository and watching the repository’s parent
directory.
    - We will log a warning if this happens.
- Empty / bogus `package.lock` files & `package-lock.json` files (and
equivalents using other package managers): if we spot a
`package-lock.json` file but it has no packages or a `package-lock.json`
w/o an associated `package.json` file. We can ignore them. This handles
the case of accidentally running `npm install` in any directory.
- Home directory detection: we can detect if we’re going to start
watching your home dir and rollback up if this is the case.
    - We will log a warning if this happens.
- If your Next config is in your home dir, we will still run your app
there as Next config is the furthest we can rollback
- NPM, Yarn, Lerna & Bun workspaces: based on the `workspaces` field in
the `package.json` or `lerna.json`

I would recommend using split-view to review. I also cleaned up the
`warnDuplicatedLockFiles()` function because it was a bit unnecessary to
repeat the full message.

Closes https://github.com/vercel/next.js/issues/92978
2026-07-28 13:35:17 -07:00
Sam PoderandGitHub 625dccbc4a Revert "[turbopack] Track re-exports in import_usage inside of compute_import_usage" (#96311)
Reverts vercel/next.js#95989
2026-07-28 20:29:13 +00:00
Zack TannerandGitHub ccfe67aa8d Return 200 for client-handled Server Action redirects (#96310)
## Summary

Client-handled Server Action redirects currently return a `303` without
a `Location` header and may include a streamed RSC response body. Some
HTTP intermediaries reject this response or strip its body because it
looks like an HTTP redirect.

Return `200` for client-handled Server Action redirects while continuing
to use `x-action-redirect` and the RSC response. Progressive-enhancement
form submissions still return a standards-compliant `303` with
`Location`.

Fixes #92882
Fixes #74026

## Verification

- `HEADLESS=true pnpm test-dev-turbo
test/e2e/app-dir/actions/app-action.test.ts
test/e2e/app-dir/app-basepath/index.test.ts
test/e2e/app-dir/actions/app-action-progressive-enhancement.test.ts`
- `HEADLESS=true pnpm test-start-turbo
test/e2e/app-dir/actions/app-action.test.ts
test/e2e/app-dir/app-basepath/index.test.ts
test/e2e/app-dir/actions/app-action-progressive-enhancement.test.ts`
- `pnpm --filter=next types`

<!-- NEXT_JS_LLM -->
2026-07-28 16:04:34 -04:00
Aurora ScharffandGitHub a28e346a1a docs(interactive-apps): update prefetching for unified runtime prefetching (#96302)
### What?

Update the interactive apps guide's prefetching section for unified
runtime prefetching.

### Why?

#96106 removed the `allow-runtime` segment config, and the guide's
section still described the old model after the mechanical rename: it
told readers session data (cookies, headers) needs the link opt-in, when
the App Shell already carries session-gated UI. Only URL data needs
`prefetch={true}`.

### How?

Rework the section around the per-link model: the shell carries static,
cached, and session output, `prefetch={true}` resolves URL data ahead of
the click, and the static prefetch attempt (#96095) makes the server
cost an internal optimization. Includes a technical-writing pass on the
section (full-noun subjects, split splices) and aligns the Next steps
table row.
2026-07-28 15:52:51 -04:00
JosephandGitHub 7ec73949fc docs: clarify instrumentation-client polyfill loading and hydration timing (#95988)
The `instrumentation-client` Polyfills docs recommended a conditional
dynamic `import().then()` to load a polyfill. That import is
fire-and-forget: Next.js loads this file synchronously and does not
await it before hydration, so the polyfill can install after components
have already run (see #83905).

- In "Execution timing" mention that only synchronous top-level code
completes before hydration. Call out that a conditional `import()` here
is not awaited, and cross-reference `supported-browsers` for
load-on-demand strategies and the built-in baseline.

- In **`supported-browsers.mdx`**, "fix" the `Conditionally loading
polyfills` example to `await import()` instead of a floating `.then()`,
otherwise, a reader needs to put their code within the `.then` chain of
the polyfill load.

Closes:
https://linear.app/vercel/issue/DOC-6506/revisit-polyfills-with-instrumentation-client
2026-07-28 15:44:03 -04:00
Sebastian "Sebbie" SilbermannandGitHub 1412d0fe91 [cd] Send Slack notification if publish fails (#96304)
Failing to publish (especially a partial publish) leaves Next.js in a
corrupted state that needs to be addressed immediately. However, we only
created alerts when deploy tests failed which requires a successful
publish.

Now we send special message to the same channel as broken canary and
deploy tests go.

This won't catch a failing deploy-target job. We'll see if deploy-target
also frequently fails/flakes.
2026-07-28 15:21:21 -04:00
Sebastian "Sebbie" SilbermannandGitHub 6ab0dd6fcd [ci] Install Node.js from the official tarball in the native-builder image (#96298)
Fixes e.g.
https://github.com/vercel/next.js/actions/runs/30314671467/job/90137708228#step:12:603

The `native-builder` image (`scripts/native-builder.Dockerfile`), used
by the `build-native` job of `build_and_deploy.yml` to cross-compile
`next-swc`, installed Node.js 20 via the NodeSource setup script. That
script downloads and imports a signing key before configuring the apt
repository. When the key download returns an HTTP 403 from CI runners
the script still exits successfully, so `apt-get install nodejs` falls
back to Ubuntu's stock `nodejs` package, which does **not** bundle
`npm`. The failure only surfaced two layers later when the image ran
`npm i -g @napi-rs/cli` (`npm: not found`, exit 127), breaking the
native build.

This change installs Node.js 20 from the official `nodejs.org` static
tarball instead. The tarball bundles `npm` and `corepack`, is
glibc-linked (matching the previous intent), and does not depend on
NodeSource's apt repository or key server, removing the flaky external
dependency. The install step also asserts `npm --version`, so a future
regression fails at the install layer rather than several layers later.


## test plan

- [x] [full build_and_deploy on this
branch](https://github.com/vercel/next.js/actions/runs/30372888336)
2026-07-28 15:21:20 -04:00
Vercel Release BotGitHubnext-js-bot[bot] <279046576+next-js-bot[bot]@users.noreply.github.com>
9ce6d48cd4 Upgrade React from 756fdd47-20260727 to 96fcba90-20260728 (#96306)
Co-authored-by: next-js-bot[bot] <279046576+next-js-bot[bot]@users.noreply.github.com>
2026-07-28 15:19:38 -04:00
Zack TannerandGitHub b368a504a8 Fix Turbopack worker URL context lookup (#96307)
## Summary

- Preserve the original static worker request when generating the
Turbopack module-context lookup, instead of passing an already-rewritten
URL object.
- Adds an e2e fixture for bare-module Worker URLs with conditional
wildcard exports.

It looks like this might have regressed in #88602

Fixes #94015
Closes #94043 

## Verification

- `cargo check -p turbopack-ecmascript`
- `HEADLESS=true pnpm test-start-turbo
test/e2e/app-dir/worker-module-url/worker-module-url.test.ts`
- `HEADLESS=true pnpm test-start-webpack
test/e2e/app-dir/worker-module-url/worker-module-url.test.ts`
2026-07-28 11:48:17 -07:00
d61f16eed3 [turbopack] Treat Object.defineProperty(exports, …, { value: … }) as side-effect free (#96273)
Treat code like this:

```
Object.defineProperty(exports, '__esModule', { value: true });
exports.foo = 1;
```

As side-effect free. This is an extension of the work on
https://github.com/vercel/next.js/pull/94293 and will allow
https://github.com/vercel/next.js/pull/95718 to drop more dead requires.

---------

Co-authored-by: Benjamin Woodruff <[email protected]>
2026-07-28 11:40:29 -07:00
David Alexandru IlieandGitHub 925edc3dd6 Classify Instant Insights as internal in Request Insights (#96147)
## Summary

- Classifies Instant Insights records as internal and hides them by
default.
- Adds a persisted “Internal activity” toggle.
- Nests internal records below their matching foreground request.
- Preserves orphaned internal records exactly once.
- Signals hidden internal errors without littering the main request
list.
- Raw endpoint and CLI data remain complete; filtering is UI-only.

## Verification

```bash
pnpm build-all
pnpm --filter=next types
pnpm --filter=next build
pnpm test-unit --runTestsByPath packages/next/src/next-devtools/dev-overlay/components/request-insights/trace-viewer.test.ts
pnpm test-dev-turbo test/development/app-dir/request-insights/request-insights.test.ts
pnpm test-dev-webpack test/development/app-dir/request-insights/request-insights.test.ts
```

<!-- NEXT_JS_LLM -->
2026-07-28 14:15:21 -04:00
David Alexandru IlieandGitHub c294cb7539 Persist Request Insights display settings (#96277)
## Summary

- Replaces the per-request verbose checkbox with a global Request
Insights settings menu.
- Persists `requestInsights.verbose` through the existing DevTools
configuration path.
- Restores the setting across reloads.
- Does not include the unrelated global `pagehide` flush behavior.

## Verification

```bash
pnpm build-all
pnpm --filter=next types
pnpm --filter=next build
pnpm test-dev-turbo test/development/app-dir/request-insights/request-insights.test.ts
pnpm test-dev-webpack test/development/app-dir/request-insights/request-insights.test.ts
```

<!-- NEXT_JS_LLM -->
2026-07-28 14:15:21 -04:00
efcbb27450 Add Instant Insights pipeline spans (#95961)
## Summary

- Adds a detached `Instant Insights` root span.
- Surfaces `Prepare validation inputs` and `Run validation` as child
phases.
- Covers both the validation worker and Webpack’s in-process path.
- Stores these spans separately from the foreground request.
- Preserves scheduling, cancellation, and concurrent-document behavior.

## Verification

```bash
pnpm build-all
pnpm --filter=next types
pnpm --filter=next build
pnpm test-unit --runTestsByPath packages/next/src/next-devtools/dev-overlay/components/request-insights/trace-viewer.test.ts
pnpm test-dev-turbo test/development/app-dir/request-insights/request-insights.test.ts
pnpm test-dev-webpack test/development/app-dir/request-insights/request-insights.test.ts
pnpm test-dev-turbo test/development/app-dir/instant-validation-scheduling/instant-validation-scheduling.test.ts
```

<!-- NEXT_JS_LLM -->

---------

Co-authored-by: David Ilie <[email protected]>
2026-07-28 14:15:21 -04:00
David Alexandru IlieandGitHub 7716976400 Isolate local Request Insights spans from OpenTelemetry (#96276)
## Summary

- Keeps Request Insights diagnostic spans inside the local recorder.
- Nested generic Next.js spans retain the local parent hierarchy.
- The user’s active OpenTelemetry context remains active and unchanged.
- Diagnostic wrappers are not delegated to or exported through user
OpenTelemetry.

## Verification

```bash
pnpm build-all
pnpm --filter=next types
pnpm --filter=next build
pnpm test-unit --runTestsByPath packages/next/src/server/lib/trace/local-span-recorder.test.ts packages/next/src/server/lib/trace/tracer.test.ts
```

<!-- NEXT_JS_LLM -->
2026-07-28 14:15:20 -04:00
David Alexandru IlieandGitHub bc856629e7 Add local Request Insights span tracing (#96275)
## Summary

- Adds a local `traceLocalSpan` primitive for Request Insights
diagnostics.
- Supports detached roots and nested local parentage.
- Records thrown errors, marks span status, rethrows, and always ends
the span.
- Keeps this foundational behavior separate from tracer/OTel
integration.

## Verification

```bash
pnpm build-all
pnpm --filter=next types
pnpm --filter=next build
pnpm test-unit --runTestsByPath packages/next/src/server/lib/trace/local-span-recorder.test.ts
```

<!-- NEXT_JS_LLM -->
2026-07-28 14:15:20 -04:00
StevenandGitHub 7c19c7c06a fix(next/image): improve test coverage for unsupported image types (#96301)
We were missing some test coverage for image optimization. This PR adds
tests for many missing image formats.

Additionally, this PR also ensures the sharp encoders match that
allowlist from detectContentType() such that future versions of sharp
that enable new encoders by default are not automatically enabled in
next/image.

Practically, there is no change to the end user because
detectContentType() runs before sharp so that is the true allowlist, but
this gives us a little more control to align the sharp allowlist as well
(since sharp can release new features in semver minor).
2026-07-28 14:05:06 -04:00
JosephandGitHub 6b572345d3 doc: typegen for typedRoutes (#96296)
`typegen` also generated the inputs needed for `typedRoutes`
2026-07-28 13:40:22 -04:00
Tim NeutkensandGitHub c23d1a946c feat(turbopack): support import.meta.env (#96225)
## Summary

- add native Turbopack support for `import.meta.env.DEV`, `PROD`,
`MODE`, `BASE_URL`, and `SSR`
- statically analyze built-in values for dead-code elimination while
exposing the complete runtime object
- derive `BASE_URL` from the Next.js `basePath` and include
Vite-compatible trailing-slash formatting
- add TypeScript declarations, focused execution and Next.js integration
coverage, and Vite migration documentation

## Verification

- `cargo fmt --all -- --check`
- `cargo nextest run -p turbopack-tests -E 'test(import_meta_env)'`
- `pnpm build-all`
- `pnpm --filter=next types`
- `NEXT_TEST_PREFER_OFFLINE=1 pnpm test-dev-turbo
test/e2e/import-meta-env/import-meta-env.test.ts`
- `NEXT_TEST_PREFER_OFFLINE=1 pnpm test-start-turbo
test/e2e/import-meta-env/import-meta-env.test.ts`

<!-- NEXT_JS_LLM -->
2026-07-28 17:34:04 +00:00