35060 Commits

Author SHA1 Message Date
next-js-bot[bot] d0ac8828c2 v16.3.2 v16.3.2 2026-08-21 09:07:01 +00:00
Sebastian "Sebbie" Silbermann 81deb92859 [16.3.x] Authenticate Turborepo remote caching with OIDC instead of a static PAT (#97603) 2026-08-20 11:13:19 -07:00
Tim Neutkens cd714d9fce [16.3.x] Fix Turbopack worker chunk loading with asset prefix (#97419)
Backports [Fix Turbopack worker chunk loading with asset
prefix](https://github.com/vercel/next.js/pull/96636) to `next-16-3`.

<!-- NEXT_JS_LLM -->

Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com>
2026-08-20 09:39:40 +02:00
Niklas Mischkulnig 5ac2327e62 [16.3] Turbopack: retain conditions when replacing resolve request keys (#97453)
Backports #97372
2026-08-19 21:58:50 +02:00
Niklas Mischkulnig 0ccb3e7f5d [16.3] Turbopack: don't trace embedded WASM loader helpers (#97353) (#97463)
Backport of https://github.com/vercel/next.js/pull/97353

Co-authored-by: vercel-fleet[bot] <308483924+vercel-fleet[bot]@users.noreply.github.com>
2026-08-18 10:08:39 +00:00
Tim Neutkens f4dc7c82ab [backport] Fix catch-all index page being served for every other slug (#97416)
Backports [Fix catch-all index page being served for every other
slug](https://github.com/vercel/next.js/pull/96553) to `next-16-3`.

<!-- NEXT_JS_LLM -->

Co-authored-by: Andrew Clark <git@andrewclark.io>
2026-08-15 16:23:36 +02:00
Hendrik Liebau eba236b5ce [backport] Scope app-entry export validation to files inside the app directory (#97357)
Backports [Scope app-entry export validation to files inside the app
directory (#97350)](https://github.com/vercel/next.js/pull/97350) to
`next-16-3`.

Fixes #96859 on the 16.3 line. The regression came from #94962, which is
present in `next-16-3` (16.3.1) and absent from `next-16-2`, so 16.3 is
the only release branch that needs it.

Clean cherry-pick with no conflicts; every touched file is
byte-identical to the merged canary commit. `cargo test -p
next-custom-transforms --test errors react_server_components` passes on
this branch (33 fixtures). The end-to-end suite is left to CI.

<!-- NEXT_JS_LLM -->

Co-authored-by: Rodrigo Arias <rodrigo@arias.me>
2026-08-14 12:51:55 +02:00
next-js-bot[bot] 3d32eb870f v16.3.1 v16.3.1 2026-08-13 22:06:37 +00:00
Jude Gao 2b4b1ec111 [backport] Revert i18n localization change for dynamic Pages API routes (#94905) (#97330)
Backports #97327 ("Revert i18n localization change for dynamic Pages API
routes (#94905)") to `next-16-3`.

Clean cherry-pick of `2f84a1f` — `next-16-3` carries the exact code
being reverted, so it applies as-is.

Restores i18n locale prefixing for dynamic Pages API routes, so the
emitted matcher and the adapter's i18n rules agree again on whether
`/api/...` carries a locale prefix. When they disagree the matcher is
unreachable and requests fall through to `/{locale}/404`.

Pairs with the adapter revert (nextjs/adapter-vercel#101, published as
`adapter-vercel@0.0.1-beta.26`). Full rationale and reproduction in
#97327.
2026-08-13 22:01:38 +00:00
Luke Sandberg 228df5fd74 [backport] Retain fewer stale cache versions and use a TTL, plus the mtime fallback (#97304)
Backports the following to `next-16-3`, as a pair:

- #96941 — "[turbopack] Retain fewer stale cache versions and use a TTL"
(`ae1e53a`)
- #97268 — "Add the mtime fallback back" (`52a3410`)

The second fixes a bug in the first: #96941 changes the `CURRENT` file
format from a bare
big-endian `u32` to a JSON object, and an existing cache directory in
the old format could no
longer be aged. #97268 adds the mtime fallback so an unparsable
`CURRENT` is aged by its mtime
instead of failing. They only make sense together, hence one branch.

Both cherry-picked with `-x`, no conflicts. Every touched source file is
byte-identical to canary.

### Verification on this branch

- `cargo check`, `cargo clippy --all-targets`, `cargo fmt --check` on
`turbo-persistence` and `turbo-tasks-backend` — clean
- `cargo test -p turbo-persistence -p turbo-tasks-backend` — all pass, 0
failures
- includes the `db_versioning` tests, notably
`test_unparsable_current_falls_back_to_mtime::case_1_old_u32_format`
(the old-format compatibility case #97268 restores)
- `cargo metadata --locked` — `Cargo.lock` consistent with the
manifests, no lockfile update needed
- `pnpm --filter=next types`, prettier, eslint — clean
- `pnpm build-all` — 18/18 tasks
- `test/production/next-server-nft` — 5/5 tests, 5/5 snapshots pass
(covers the traced `turbopack-cache-seed.js`)

### End-to-end verification against a real old-format cache

`create-next-app@16.3.0` + `next build` (with
`turbopackFileSystemCacheForBuild`) on released
`next@16.3.0` writes a `CURRENT` in the old pre-JSON format — a bare
big-endian `u32`
(`0000 0008`), 30M cache. This branch was then applied with
`pnpm pack-next -p <app> -- --release` (release binary confirmed to
contain
`TURBO_ENGINE_VERSION_TTL_DAYS` and the new `CURRENT` field names), and
two arms were run from
an identical starting state — same cache, same code, only the env var
differing:

| Arm | Build | Cache dirs after |
| --- | --- | --- |
| `TURBO_ENGINE_VERSION_TTL_DAYS=0` | exit 0 | old dir **deleted**, 1
remains |
| default TTL (3 days) | exit 0 | old dir **retained**, intact at 30M, 2
remain |

The retention arm is the meaningful control: without #97268's fallback,
`read_current_version`
would error on the bare-`u32` file, the age would become
`Duration::MAX`, and the directory would
be evicted in *both* arms. Retention under the default TTL is direct
evidence the mtime fallback
works.

Also confirmed:

- new `CURRENT` is written as JSON:
`{"max_sequence_number":8,"commit_time":"..."}`
- retention cap holds: seeded 4 version dirs → build left exactly 2
(current + one most-recently-used other)
- clean deletion, no `DELETION_PREFIX` leftovers in any run
- `TURBO_ENGINE_VERSION_TTL_DAYS=notanumber` warns (`expected a whole
number of days`) and falls back to the 3-day default rather than failing

<!-- NEXT_JS_LLM -->
2026-08-13 21:43:26 +00:00
Andrew Clark 16eab3ac5d [backport] Fix: Optimistic routing bugs leading to repeated prefetch loops (#97325)
Backports #97128 ("Fix: Optimistic routing bugs leading to repeated
prefetch loops") to `next-16-3`.

Fixes an infinite prefetch loop in optimistic routing. A proxy that
rewrites every URL to inject a leading path segment — i18n with the
default locale hidden from the URL, so `/one/two` is served as
`/en/one/two` — combined with a fully dynamic target route like
`/[locale]/[...pages]`, produces a prefetch that never settles. When a
prefetch response came back, the client never checked whether the
rendered tree matched the one it had requested. When the params baked
into the request were wrong because of the rewrite, the task kept
re-attempting to fulfill the missing data and looped forever.

The prefetch path now records a dynamic-rewrite marker on the local
route definition when the response's tree diverges from the requested
one, which disables further optimistic resolution of that route and
invalidates the entries derived from it. This is the same strategy
normal navigation responses already used, now applied to the prefetch
path.

A second, related bug is also fixed: parallel routes with conflicting
dynamic params at the same level (`@modal/[...catchAll]` next to
`[username]`) can't be distinguished by the traversal algorithm, which
assumes each segment resolves independently without inspecting sibling
branches. When that scenario is detected, optimistic routing is now
disabled for the conflicting route rather than binding one branch's URL
parts to another branch's params.

### Verification on this branch

Cherry-picked from `5942b37a42`. Three source files conflicted, all
because `next-16-3` predates the post-16.3.0 refactor that split the
client's response decoder into its own module:

- `segment-cache/decode-server-response.ts` — this file does not exist
on this branch; it was extracted out of `navigation.ts` after 16.3.0.
Its change (tracking whether the decoded tree's segment identities
diverge from the base request tree) was ported into `navigation.ts`,
where the equivalent logic still lives. Canary decodes a compact
transport tree and compares segment identities inline during the walk;
this branch instead merges the response patch onto the base
`FlightRouterState` before converting it to a `RouteTree`. The check is
therefore re-expressed as a read-only walk in
`convertServerPatchToFullTree` that compares each server patch against
the base tree it is applied to, following canary's descent
(`convertServerPatchToFullTreeImpl`) exactly and using the same
comparison rules: segment identity via `matchSegment`, page segments
matched modulo embedded search params, server-filled `__DEFAULT__`
segments ignored, and inactive parallel-route branches (those carrying a
refresh state in the base) skipped. The result is threaded out through
`NavigationSeed.treeDivergedFromBase`.
- `segment-cache/cache.ts` — the consuming block in
`fetchSegmentPrefetchesUsingDynamicRequest` (mark-as-dynamic-rewrite,
invalidate derived entries, reject with immediate expiry) is
byte-identical to canary. The surrounding conflicts were only
incidental: the `RouteTreeAccumulator` type gaining
`treeDivergedFromBase`, and canary's transport-decoder call vs. this
branch's `convertRootFlightRouterStateToRouteTree`. Resolved by keeping
this branch's calls and adding the new field to the accumulators.
Canary's inline `NavigationSeed` construction in
`writeDynamicTreeResponseIntoCache` does not apply here because that
function delegates to `convertServerPatchToFullTree`, which now carries
the field.
- `router-reducer/create-initial-router-state.ts` — a one-line
accumulator initializer; kept this branch's
`convertRootFlightRouterStateToRouteTree` call and added
`treeDivergedFromBase: false`.

The other touched source files applied cleanly and are byte-identical to
canary: `segment-cache/optimistic-routes.ts` (the parallel-route
conflict detection) and `route-params.ts` (exporting
`canonicalizeURLPart`), along with `ppr-navigations.ts`, the small
cleanly-applied hunk in `navigation.ts`, and every test fixture.

`tsc` passes on the `next` package for all files touched here.
Behavioral verification is left to CI on this branch; the change carries
the `proxy-prefix-rewrite-prefetch-loop` and
`modal-catchall-sibling-dynamic-prefetch-loop` end-to-end suites plus
additions to the `optimistic-routing` suite.

Opened as a draft because the `decode-server-response.ts` →
`navigation.ts` port is a manual re-implementation across the refactor
boundary rather than a mechanical cherry-pick. The divergence walk in
`convertServerPatchToFullTree` is the part most worth a close review.

<!-- NEXT_JS_LLM -->
2026-08-13 17:17:46 -04:00
Andrew Clark 75548c9a2b [backport] Fix Nav Inspector request loop on repeat captures (#97326)
Backports #97050 ("Fix Nav Inspector request loop on repeat captures")
to `next-16-3`.

With the Nav Inspector enabled, clicking a `<Link prefetch={true}>`,
closing the inspector, navigating home, re-enabling it, and clicking the
same link left the app hung in a pending "Compiling…" state while it
fired prefetch requests in an infinite loop (~30/sec). The Instant
Navigation Testing lock restricted navigation reads to entries created
within the current lock scope (`ownedEntries`), enforced as a post-hoc
filter after the cache lookup. Because the segment cache resolves
lookups by most-specific-match, a previous scope's runtime-prefetch
entries at concrete param keypaths kept winning the lookup, the filter
kept rejecting them, and the locked prefetch created its replacement at
a more generic keypath that could never win — so every scheduler pass
discarded and refetched forever.

Rather than patch the filter, the fix replaces the `ownedEntries`
mechanism with a per-scope segment `CacheMap`. Each lock scope owns a
private map that starts empty and is discarded at release, so a captured
navigation structurally observes only data fetched under the lock. The
map is bound to a unit of work when it is created: a prefetch task
captures its map when scheduled (`PrefetchTask.segmentCacheMap`, the
single place that consults lock state), a locked navigation inherits its
driving task's map, and everything else — unlocked navigations,
hydration, refreshes, history-traversal restores, server actions and
patches — binds to the shared map. Reads and response writes receive the
map explicitly, so a request that straddles a scope boundary still
writes into the map its entries live in.

In production builds without the testing API this compiles down to the
previous single-map behavior, so the non-testing paths are unchanged.

### Verification on this branch

Cherry-picked from `5dc3ae1fe7`. Three files conflicted; each was
resolved by keeping the release branch's existing code shape and
applying only the fix's actual change — threading the segment `CacheMap`
through as an explicit parameter.

- **`refresh-reducer.ts`** and **`restore-reducer.ts`** — the conflicts
were confined to the import block. Canary imports
`convertServerPatchToFullTree` from
`./segment-cache/decode-server-response`, a module that doesn't exist on
this branch; `next-16-3` still imports it from
`./segment-cache/navigation`. I kept the release branch's import source
and added the new `segmentCacheMap` import alongside it. The
function-body changes (passing `segmentCacheMap` as the shared map)
applied cleanly, and the `startPPRNavigation`/`spawnDynamicRequests`
argument order lines up with this branch's signatures.

- **`cache.ts`** — the substantive one. `next-16-3` predates the
post-16.3.0 segment-cache refactors, so three areas differ from canary
and had to be adapted rather than taken verbatim from the patch: (1)
`RouteTree` is still non-generic here (`RouteTree`, not
`RouteTree<RSCSegmentData | null>` — this branch has no `RSCSegmentData`
and the tree doesn't carry render data), so the three signatures the
patch retyped were kept as plain `RouteTree`; (2)
`writeSegmentBundleResponse` still has the older `StaticShell`/`else`
re-key split guarded by `__NEXT_VARY_PARAMS`, versus canary's single
`upsertSegmentEntry` — I kept the release-branch logic and threaded
`map` into both of its `upsertSegmentEntry` calls; (3)
`writeDynamicRenderResponseIntoCache` and `writeSeedDataIntoCache` still
use the `flightDatas` + `CacheNodeSeedData` write model rather than
canary's route-tree-carries-data model — I kept the release-branch
traversal and threaded `map` into each `writeSeedDataIntoCache` /
`fulfillEntrySpawnedByRuntimePrefetch` call. Everything else in
`cache.ts` — the `ownedEntries` removal, the `segmentCacheMap` export,
`insertEmptySegmentCacheEntry`, and the `map` parameter added to every
read/write helper — applied cleanly and is identical to canary. I
confirmed no stale references to the removed `ownedEntries` /
`readSegmentCacheEntry` / `navigationLockPrefetch`-param APIs remain,
and that every call site of the retyped helpers passes a map.

The remaining files applied without conflict. `server-patch-reducer.ts`,
`navigation-testing-lock.ts`, `navigation-testing-lock.disabled.ts`, and
the `instant-navs-devtools` test are byte-identical to canary.
`create-initial-router-state.ts`, `ppr-navigations.ts`,
`server-action-reducer.ts`, `navigation.ts`, and `scheduler.ts` differ
from canary only in pre-existing `next-16-3` divergence (the older
transport-data / route-tree models); the fix's own hunks (the
`segmentCacheMap` threading) applied to them cleanly. No local typecheck
was run — this fresh worktree has no `node_modules` and installing it
carries the known corepack/SWC-binary gotchas — so behavioral and type
verification is left to CI on this branch, which carries the
`instant-navs-devtools` regression test from #96692.

**Reviewer, focus here:** the `writeSegmentBundleResponse` resolution in
`cache.ts` (area 2 above) is the hunk I'd most like a second pair of
eyes on. I preserved this branch's `StaticShell`/`else` re-key branch
structure and only inserted the `map` argument into its two
`upsertSegmentEntry` calls; please confirm that routing both branches'
writes through the task's bound map (rather than the module-level
`segmentCacheMap`) is the correct behavior for the older re-key logic.

<!-- NEXT_JS_LLM -->

Co-authored-by: Sam Selikoff <sam.selikoff@gmail.com>
2026-08-13 17:17:27 -04:00
Luke Sandberg f6bd714a79 [backport] [test] Compile the middleware redirect routes up front in dev (#97328)
Backports #97190 ("[test] Compile the middleware redirect routes up
front in dev") to `next-16-3`.

<!-- NEXT_JS_LLM -->

Co-authored-by: Hendrik Liebau <mail@hendrik-liebau.de>
2026-08-13 21:11:14 +00:00
Sebastian "Sebbie" Silbermann 43c1c60bca [16.3] [ci] Use OIDC tokens to read private preview builds (#97258)
Backports https://github.com/vercel/next.js/pull/96919

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-13 14:00:45 -07:00
Hendrik Liebau 9dbb357dbe [backport] Encode the cache item name built by unstable_cache (#97313)
Backports #96936 ("[refactor] Rename `encodeCacheTag` to
`encodeHeaderSafe`") and #96937 ("Encode the cache item name built by
`unstable_cache`") to `next-16-3`.

Fixes #76286. A cache implementation may serialize cache metadata into
HTTP request headers, whose values are limited to Latin-1.
`unstable_cache` assembles a cache item name from the request URL and
the name of the cached callback, and neither part was encoded. When that
name holds a character above U+00FF the conversion throws before the
request is dispatched, so the read never reaches the cache and the write
that follows it fails the same way. Nothing is stored, nothing is found,
and the entry falls back to the origin on every render.

The reachable case is a non-ASCII query parameter on any dynamic route
that calls `unstable_cache`, whether or not the route reads
`searchParams`, because `URLSearchParams` returns decoded keys and
values while the pathname stays percent-encoded.

The rename is folded in because it is the prerequisite: #96937 imports
`encodeHeaderSafe` from `server/lib/encode-header-safe`, which the
rename creates. It carries no behavior change, the function body is
identical apart from the parameter name, and the two were stacked in
this same order on canary.

### Verification on this branch

Cherry-picked from `1f0cd93b83` and `4286a42e2c` in that order, with no
conflicts.

`packages/next/src/server/web/spec-extension/unstable-cache.ts` is not
byte-identical to canary, because the release branch predates the
unrelated `willConsumerServerCache` change and keeps
`workStore.isStaticGeneration` at those two call sites. The diff this
backport applies to that file is exactly the encoding change and nothing
else. Every other source file is byte-identical to canary, and no
reference to the old `encodeCacheTag` name remains.

Behavioral verification is left to CI on this branch; the change carries
the `non-ascii-cache-item-name` end-to-end suite, which exercises a real
cache handler.

<!-- NEXT_JS_LLM -->
2026-08-13 15:59:11 -04:00
Hendrik Liebau 323a17c1b3 [backport] Discard only cache entries that predate a tag revalidation, and reuse completed entries (#97314)
Backports #96726 ("Discard only cache entries that predate a tag
revalidation") and #96727 ("Reuse completed cache entries for the rest
of a request") to `next-16-3`.

Calling `updateTag()` in a server action made every later read of a
cache carrying that tag regenerate for the remainder of the request,
including reads of an entry that had just been generated after the
invalidation and therefore already reflected it. Two sequential reads of
the same cache function during the re-render produced two different
values within a single render, and each one repeated the work.
`isRecentlyRevalidatedTag` only asked whether a tag appeared in
`pendingRevalidatedTags`, and that array lives for the whole
`WorkStore`, which spans a server action and the render that follows it.
Each pending revalidated tag now records a `revalidatedAt` timestamp
taken from the same clock as `CacheEntry.timestamp`, and the renamed
`isRevalidatedAfter` reports an entry as stale only when the
revalidation is newer than the entry.

The second change fixes a `'use cache: private'` function executing its
body twice when it is called twice in one request, which defeats the
preload-then-read shape that motivates a preload in the first place. The
intra-request dedupe map dropped an entry as soon as its fill completed,
so it only ever covered concurrent invocations, and private caches have
no cache handler in production to fall back to. Completed invocations
now move into `completedCacheInvocations` on the work store instead of
being dropped.

The two are backported together because #96727 builds on the discard
checks that #96726 restructures. They were stacked in this order on
canary, and #96727 conflicts in
`test/e2e/app-dir/use-cache/use-cache.test.ts` when applied alone.

### Verification on this branch

Cherry-picked from `5da1c1ae03` and `1ff6a80358` in that order, with no
conflicts. All source files are byte-identical to canary. Behavioral
verification is left to CI on this branch; the changes carry the
`action-dedupe`, `dedup-sequential` and `private-dedup-sequential`
fixtures in the `use-cache` suite, and a handler-call count assertion in
`use-cache-custom-handler`.

<!-- NEXT_JS_LLM -->
2026-08-13 19:58:49 +00:00
Hendrik Liebau 6d67f46a4d [backport] Keep the dev validation worker alive across HMR updates (#97315)
Backports #96988 ("Keep the dev validation worker alive across HMR
updates") to `next-16-3`.

Cache Components dev validation reported stack frames that pointed at
build output whenever a module had been updated while the dev server
ran. The overlay showed a raw `file:` URL, the terminal named the chunk
rather than the page, and because the frame never resolved to a source
position there was no code frame either, so nothing indicated which line
caused the error. This affected both the static shell validation and the
instant-navigation validation, since both run on the same worker.

Turbopack's server HMR evaluates an updated module as a script of its
own, carrying its source map inline rather than on disk, so only the
isolate that ran that `eval` can resolve a frame in it. The validation
worker never ran it. The worker now replays the applied updates, the
cleared manifest cache entries, and the evicted paths that the dev
server reports, in the same order the dev server applied them, which
leaves each updated module's inline source map in the worker's own
Node.js cache.

Not dropping the worker on every edit also removes a worker respawn and
a `loadComponents` call from each validation that follows an edit, which
is paid at exactly the moment the user is waiting for the insight. The
case in the test suite that covers this went from around 870ms to around
240ms.

This affects Turbopack dev with Cache Components, which is on by default
unless `experimental.devValidationWorker` is set to `false`.

### Verification on this branch

Cherry-picked from `f70564f742` with no conflicts. All source files are
byte-identical to canary. Behavioral verification is left to CI on this
branch; the change carries the `dev-validation-worker-source-maps`
suite, whose snapshots turn from a frame naming the chunk into resolved
frames.

<!-- NEXT_JS_LLM -->
2026-08-13 15:58:43 -04:00
Hendrik Liebau 2dd7f52863 [backport] Allow literal exports in 'use cache' files (#97312)
Backports #97181 ("Allow literal exports in `'use cache'` files") to
`next-16-3`.

A `'use cache'` page or layout that exports a route segment config
literal, such as `export const instant = false`, `export const
dynamicParams = true`, `export const prefetch = 'partial'`, or `export
const maxDuration = 5`, fails the build with "Only async functions are
allowed to be exported in a "use cache" file".

Rejecting exported literals is meaningful only in a `'use server'` file,
where every export becomes a server reference and a runtime check
asserts that each one is a function. A `'use cache'` file wraps only
exports that are, or might be, functions, so known non-function values
can pass through. The check is now scoped to `in_action_file`.

### Verification on this branch

Cherry-picked from `c0c64a0ab1` with no conflicts. All source files are
byte-identical to canary. This touches `crates/next-custom-transforms`,
so the release build needs the native binary rebuilt. Behavioral
verification is left to CI on this branch; the change carries transform
fixtures on both the server and client graph.

<!-- NEXT_JS_LLM -->
2026-08-13 15:58:40 -04:00
Hendrik Liebau c19a64dcff [backport] Restore the live headers() view of the incoming request (#97311)
Backports #97166 ("Restore the live `headers()` view of the incoming
request") to `next-16-3`.

Fixes #97049. This is a regression introduced in 16.3.0 itself. #94703
and #95116 are both in the `v16.3.0` tag, and between them they left
`headers()` detached from the request it describes. A Proxy that writes
a header onto `request.headers` and then reads it back through
`headers()` gets the value from before the write, while reading the same
header directly off `request.headers` returns the new value, so two APIs
describing the same request disagree. Whether the write is seen at all
depends on ordering, because the view is built on first access.

`HeadersAdapter.seal` now accepts a set of header names to omit from
every read operation, and `getHeaders` seals the shared request headers
directly instead of stripping them from a copy. Both earlier intentions
survive: the internal headers stay on the request where the framework
still reads them, they stay invisible to userland `headers()`, and the
sealed view tracks the request again.

### Verification on this branch

Cherry-picked from `3c97df56ea` with no conflicts. All source files are
byte-identical to canary. Behavioral verification is left to CI on this
branch; the change carries unit coverage in `headers.test.ts` and the
`proxy-headers-live-view` end-to-end suite.

<!-- NEXT_JS_LLM -->

Co-authored-by: joaquin <tachsinachmet@gmail.com>
2026-08-13 15:54:32 -04:00
Luke Sandberg 98b487c2d3 [backport] [turbopack] Fix HMR for dynamic imports evaluated from layouts (#97317)
Backports #97213 ("[turbopack] Fix HMR for dynamic imports evaluated
from layouts") to `next-16-3`.

Async chunks that the caller had already expanded (e.g. those reachable
from concatenated chunk
groups) were not tracked in the chunk list, so an edit inside one of
them produced no HMR update at
all. This shows up with the common `await
import(\`../../messages/${locale}.json\`)` pattern in a
layout.

Cherry-picked from 04e9933b33 with no
conflicts. All 8 files are
byte-identical to canary.

### Verification on this branch

- `cargo fmt --check -p turbopack-nodejs` — clean
- `cargo check -p next-api`, `cargo clippy -p next-api` — clean (these
build `turbopack-nodejs`
  with its real feature set)
- `pnpm build-all` — 18/18 tasks
- `test/development/app-dir/layout-dynamic-import-hmr` — passes with
Turbopack and with webpack
- `test/development/acceptance-app/{app-hmr-changes,ReactRefreshModule}`
— 2/2 pass

The new test was confirmed to actually cover the fix: reverting only the
two Rust files (keeping the
fixture) makes it fail with `Expected: "updated" / Received:
"original"`, and restoring them makes it
pass again.

Note: `cargo check -p turbopack-nodejs` in isolation fails on
`turbopack-node/src/pool_stats.rs`
with an unresolved `tokio`. That reproduces identically on unmodified
`next-16-3` and is present on
canary too (`mod pool_stats;` is ungated while `tokio` is optional
behind `process_pool`/
`worker_pool`), so it is pre-existing and unrelated to this backport.

<!-- NEXT_JS_LLM -->

Co-authored-by: Sam Poder <sampoder@berkeley.edu>
2026-08-13 19:09:25 +00:00
Luke Sandberg d2aa1b63d2 [backport] Fix missing styled-jsx styles in Pages Router SSR on adapter builds (#97302)
Backports #96632 ("Fix missing styled-jsx styles in Pages Router SSR on
adapter builds") to `next-16-3`.

Cherry-picked from 2049354a66 with no
conflicts.

### Verification on this branch

- `cargo check -p next-api`, `cargo clippy -p next-api`, `cargo fmt
--check -p next-api` — clean
- `pnpm --filter=next types` — clean
- `test/production/adapter-styled-jsx` — passes with both Turbopack and
webpack
- `test/production/adapter-root`, `adapter-config`,
`adapter-config-i18n` — pass (no regression from the `trace_endpoint`
signature change)

<!-- NEXT_JS_LLM -->

Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com>
Co-authored-by: vercel-fleet[bot] <308483924+vercel-fleet[bot]@users.noreply.github.com>
Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com>
2026-08-13 12:05:30 -07:00
Luke Sandberg fc7ae17207 [backport] [turbopack] Raise registration calls in hoisted modules to the top (#97308)
Backports #96697 ("[turbopack] Raise registration calls in hoisted
modules to the top") to `next-16-3`.

Fixes #96648: when a scope-hoisting group enters a second group that
depends back on the first, the
re-entry happened before the first group's module registrations had run.
Non-scope-hoisted modules
with cycles already raise the registration call to the top of the
factory; this restores that for
scope-hoisted modules.

Cherry-picked from 40680b9568 with no
conflicts. All 16 files are
byte-identical to canary.

### Verification on this branch

- `cargo check`, `cargo clippy --all-targets`, `cargo fmt --check` on
`turbopack-ecmascript` — clean
- `cargo test -p turbopack-tests --test execution` — 255 passed, 0
failed, including the new
  `scope_hoisting__reentrant_group` fixture
- `cargo test -p turbopack-tests --test snapshot` — 113 passed, 0
failed; the working tree stays
clean afterwards, so the 5 updated snapshots match the generated output
exactly
- `pnpm build-all` — 18/18 tasks
- `test/e2e/app-dir/app/index.test.ts` (Turbopack, production) — 116
passed, 5 skipped

The snapshot updates are the intended effect of the change:
`__turbopack_context__.s([...])` now
precedes the merged-module bodies instead of following them.

<!-- NEXT_JS_LLM -->

Co-authored-by: Sam Poder <sampoder@berkeley.edu>
2026-08-13 14:03:03 -05:00
Niklas Mischkulnig ec2b319781 [backport] Bump @swc/helpers (#96885)
Backport https://github.com/vercel/next.js/pull/96720
2026-08-07 13:31:53 -07:00
Sebastian "Sebbie" Silbermann ced8d73dae [16.3.x] Default deploy e2e tests to the repo next version (#96900)
Backports #96895 to `next-16-3`. The workflow file on this branch is
identical to canary's, so the change applies unchanged.
2026-08-07 17:34:54 +00:00
Steven 3f07d5eabc [16.x] fix(next/image): preserve image response after optimization (#96733)
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: Steven <229881+styfle@users.noreply.github.com>
2026-08-06 07:49:00 +02:00
Sam Poder b20f297aef [backport] [turbopack] Collapse nested promises in the analyzer (#96675)
Backports #96601 ([turbopack] Collapse nested promises in the analyzer)
to `next-16-3`.


<!-- NEXT_JS_LLM -->
2026-08-04 14:13:17 -07:00
Luke Sandberg 6b3677887a [backport] [turbopack] Add turbopack_ecmascript and turbopack_wasm's embeded FS to internal_assets_conditions (#96655)
Backports #96600 ([turbopack] Add `turbopack_ecmascript` and
`turbopack_wasm`'s embeded FS to `internal_assets_conditions`) to
`next-16-3`.


<!-- NEXT_JS_LLM -->

Co-authored-by: Sam Poder <sampoder@berkeley.edu>
2026-08-04 18:38:30 +00:00
Luke Sandberg a4b5ee75da [backport] Turbopack: don't strip async-module runtime from shared runtime chunks (#96653)
Backports [#96599](https://github.com/vercel/next.js/pull/96599)
("Turbopack: don't strip async-module runtime from shared runtime
chunks") to `next-16-3`.


<!-- NEXT_JS_LLM -->
2026-08-04 18:27:12 +00:00
next-js-bot[bot] a104728586 setup release branch 2026-08-04 17:44:58 +00:00
next-js-bot[bot] d73f5622e2 v16.3.0 v16.3.0 2026-08-03 20:06:44 +00:00
Joseph 2e0d4cbe5d Edits to turbopackFileSystemCache (#96531)
- Rework the
`/docs/app/api-reference/config/next-config-js/turbopackFileSystemCache`
API reference.
- Adjust the table notes in
`/docs/app/api-reference/turbopack#configuration` — `[^1]` works well,
but the table notes are auto-magically placed at the bottom of the page.
Going with this hand rolled table notes for now.
- Tidy the Build Caching section in
`/docs/app/api-reference/turbopack#configuration`
- Update the Upgrade to version 16 section on dev/build cache
- Removed the `Build caching` from Webpack gaps
  - Added Filesystem caching to Performance and Fast Refresh
2026-08-03 22:04:23 +02:00
Joseph 86df9c7588 docs: cover direct visits and client navigations in the instant() e2e example (#95803)
Reworks the instant-navigation guide's e2e testing example to cover both
ways a route is reached: a direct visit (SSR document load) and a client
navigation.

Each test wraps the navigation in `instant()` and asserts the shell
renders while the streamed content is held back, then appears after.

Also documents where the testing API is available: automatically under
`next dev`, and in a production build via
`experimental.exposeTestingApiInProductionBuild`.

Closes:
https://linear.app/vercel/issue/DOC-6477/instant-e2e-helper-for-ssr-and-soft-navs-snippets-show-difference

---------

Co-authored-by: Aurora Scharff <aurora.sofie@gmail.com>
Co-authored-by: Aurora Scharff <66901228+aurorascharff@users.noreply.github.com>
2026-08-03 22:00:06 +02:00
Sam Poder 47a52c0d6b [turbopack / next.js] Add an end-to-end test for new root detection (#96544)
Follow-up PR to https://github.com/vercel/next.js/pull/96159, adding an
end to end test that specifically tests the new stuff in that PR!
2026-08-03 12:58:53 -07:00
Andrew Clark 8e878d4848 Remove implicit Partial Prefetching opt-in from instant (#96539)
Previously, adding a truthy `instant` config to a route segment (e.g.
`export const instant = true`) did two things: it enabled instant
navigation validation, and it implicitly opted the route into Partial
Prefetching.

Now those concerns are fully separate. `instant` only controls
validation, so enabling it no longer silently changes how a route is
prefetched. Partial Prefetching is enabled with the `prefetch` segment
config (`'partial'` or `'unstable_eager'`), or globally with the
`partialPrefetching` option in next.config.

For routes whose only opt-in was a truthy `instant`, `<Link
prefetch={true}>` goes back to performing a legacy full prefetch instead
of being downgraded to a partial one. `instant = false` still opts a
route out of the dev-time `prefetch={true}` warning.

Adds a regression test asserting that a route that only exports `instant
= true` keeps the full-prefetch behavior.
2026-08-03 19:56:47 +00:00
Tim Neutkens e37ddd19f5 Fix deploy test TypeScript exclusions (#96545)
## Summary

Set `NEXT_PRIVATE_LOCAL_DEV=1` for directory fixtures in deploy mode,
matching the next-start setup. This keeps copied test runner files
excluded from TypeScript checks when deployment tests use
`tsconfig.test.json`.

## Verification

- `pnpm exec tsc --project test/lib/tsconfig.json --noEmit`
- Not run: deployment tests (requires Vercel deployment credentials)

<!-- NEXT_JS_LLM -->
2026-08-03 19:35:17 +00:00
Aurora Scharff 8a4920c15a docs: clarify first-party Skills workflows (#96495)
## Summary

- clarify how runtime foundations, interactive workflows, and unattended
loops fit into the AI agents and Instant Navigation guides
- harden the Cache Components and Partial Prefetching Skills around
capability checks, trustworthy `instant()` tests, route scope, and
real-app verification failures
- add migration-guide comments to temporary Partial Prefetching route
config and update `remove-partial-prefetch` to remove only generated
comments while preserving runtime-prefetch TODOs and user comments

This keeps the experimental Partial Prefetching optimizer in #96471
separate.

## Testing

- `pnpm --filter @next/codemod build`
- `pnpm --filter @next/codemod test --
transforms/__tests__/remove-partial-prefetch.test.js --runInBand`
2026-08-03 19:23:56 +00:00
Marcos Hernanz 4344b83a6b Flag newly disabled deploy tests (#96505)
## What changed

Added scoped review guidance under `test/` so Vercel Agent flags changes
that newly disable deploy-mode tests or assertions.

## Why

Deploy coverage should only be disabled for assertions that are
inherently self-hosted-specific. When deployed behavior differs, the
test should prefer documenting those semantics instead of skipping
deploy mode.

## Validation

- `pnpm install --frozen-lockfile`
- `pnpm build-all`
- Hosted Vercel Agent E2E: an intentional `skipDeployment: true` probe
was flagged inline, then removed
- Hosted Vercel Agent Review passed on the final diff
2026-08-03 19:29:36 +02:00
Joseph 459617a125 fix: double fragment on navigation (#93132)
Fixes: https://github.com/vercel/next.js/issues/93126,
https://github.com/vercel/next.js/issues/95551

Repro:

- from `/` navigate to `/abc#foo`
- on `/abc#foo` - now click `/abc#bar`
- the url is now at `/abc#foo#bar`

Unlike, https://github.com/vercel/next.js/pull/93855, this PR fixes what
gets stored in the segment cache navigation, rather than slicing away an
existing hash. It is plausible that dropping the hash from the segment
cache is not desired though.
2026-08-03 18:21:06 +02:00
Tim Neutkens cbf0cef687 Enable TypeScript CLI by default (#96497)
## Summary

Enable the project-local TypeScript CLI checker by default during `next
build`, while preserving `experimental.useTypeScriptCli: false` as an
opt-out to the TypeScript compiler API. Update the TypeScript 7
guidance, diagnostics, tests, and documentation to match the new
default.

## Verification

- `pnpm exec jest --runTestsByPath test/unit/isolated/config.test.ts`
- Pre-commit lint-staged checks passed (Prettier and ESLint)
- Not run: `pnpm test-start-turbo
test/production/app-dir/typescript-cli/typescript-cli.test.ts` (isolated
fixture dependency installation was blocked by unavailable npm registry
access)
- Not run: `pnpm --filter=next types` (repository has pre-existing
unrelated TypeScript errors)

<!-- NEXT_JS_LLM -->
2026-08-03 18:10:51 +02:00
Zack Tanner dcdacfd036 test: skip hybrid not-found coverage for the legacy builder (#96534)
## Summary

The `pages-router-app-not-found` test verifies behavior implemented by
the Next.js adapter. The legacy `@vercel/next` builder has a
pre-existing behavior where it prefers the Pages Router error page for
this hybrid routing case.

Skip this test when deployment tests run without the adapter. It will
continue running in development, `next start`, and adapter deployment
tests.

## Verification

- `NEXT_TEST_MODE=deploy NEXT_ENABLE_ADAPTER=0 pnpm testheadless
test/e2e/app-dir/pages-router-app-not-found/pages-router-app-not-found.test.ts`
- `pnpm testheadless
test/e2e/app-dir/pages-router-app-not-found/pages-router-app-not-found.test.ts`
2026-08-03 08:36:57 -07:00
Joseph 2aef3b816f docs: ISR with Cache Components and Partial Prefetching (#96526)
App Shell upgrade for prerendered fallbacks, are now gated behind
`partialPrefetching`.
2026-08-03 17:15:00 +02:00
David Alexandru Ilie da90782311 Fix App Router scroll padding visibility (#96308)
## Summary

- Treat the root `scroll-padding-top` as the lower boundary of the
usable viewport during App Router navigations, so content obscured by a
sticky header is not incorrectly considered visible.
- Preserve the merged Fragment scroll-ownership state machine: empty
Fragments remain unavailable targets, while real targets are classified
against the padding-aware viewport.
- Resolve pixel and percentage values and use the same visibility rule
in both the legacy element handler and the Fragment-ref handler.
- Add regression coverage showing that Next scrolls when the destination
is hidden inside the padding boundary, while preserving the current
scroll position when the destination is genuinely visible below it.

## Performance

The root computed style is resolved lazily, only after the candidate
produces client rects. Empty Fragments and hash navigations do not
perform this lookup. For a real route-scroll target, the resolved value
is cached locally and reused by the second geometry check after
`scrollTop = 0`.

This does not add work to scroll events or every render, and keeping the
value local allows responsive CSS, root classes, and custom properties
to change between navigations. In a 50-iteration dirty-style Chromium
probe, both the existing and updated paths reported 50 style
recalculations and 50 layouts, indicating that the lookup reused the
style/layout update already required by the handler in that test.

## Related work

#96342 is now merged into `canary` and handles empty Fragment scroll
ownership. This PR composes with its `NoClientRects` / `InViewport` /
`OutOfViewport` state machine by changing only the visible-region
boundary for real targets.

## Verification

- `HEADLESS=true pnpm test-dev-turbo
test/e2e/app-dir/router-autoscroll/router-autoscroll.test.ts -t "scroll
padding"` (3/3)
- `HEADLESS=true __NEXT_EXPERIMENTAL_APP_NEW_SCROLL_HANDLER=false pnpm
test-dev-turbo
test/e2e/app-dir/router-autoscroll/router-autoscroll.test.ts -t "scroll
padding"` (3/3)
- `HEADLESS=true pnpm test-dev-turbo
test/e2e/app-dir/parallel-routes-scroll-owner/parallel-routes-scroll-owner.test.ts`
(8/8)
- `HEADLESS=true pnpm test-dev-webpack
test/e2e/app-dir/parallel-routes-scroll-owner/parallel-routes-scroll-owner.test.ts`
(8/8)
- `HEADLESS=true pnpm test-dev-turbo
test/e2e/app-dir/navigation-focus/navigation-focus.test.ts` (5/5)
- Manually compared the same sticky-header reproduction before and after
the change.

<!-- NEXT_JS_LLM -->
2026-08-03 16:00:14 +01:00
Hendrik Liebau c00449d52b [ci] Wait for the preview tarballs before running the deploy tests (#96527)
The "Test new and changed tests when deployed" jobs install Next.js from
the preview tarballs built for the commit under test, but nothing made
them wait for those tarballs to exist. Until #96438 the job was ordered
behind `test-prod` and the other new-test jobs, which delayed it long
enough that the tarballs had usually landed by the time it looked for
them. Now that it starts immediately it frequently fails with "Artifacts
not found for commit ...".

The ordering cannot be expressed as a `needs:` entry, because the
tarballs are published by a different workflow and, for pull requests
from branches in this repository, a different event than the
`build-and-test` run that consumes them. We therefore add a
`wait-for-preview-tarball` job that polls for the tarball instead, and
make both deploy test jobs depend on it. Doing the waiting in one cheap
job keeps the deploy test matrices off their 16-core runners until there
is something for them to install.

The new job is also listed in `tests-pass`. A dependency failure skips
the jobs that need it, and a skipped job does not count as a failure, so
without that entry a tarball that never arrives would have let the
required check pass with the deploy tests never having run.

`test-new-tests-deploy-cache-components` gets the same treatment,
dropping the incidental ordering it still inherited from
`test-cache-components-prod` and picking up the docs-only guard that
`test-new-tests-deploy` already had.
2026-08-03 16:27:51 +02:00
Steven 767e0e98db [turbotrace] bump test version of sharp (#96386)
Regenerate the lockfile to test if the previous PR still works with the
latest sharp

- https://github.com/vercel/next.js/pull/94845
2026-08-03 15:42:02 +02:00
Janka Uryga 331739243f [Cache] Make caches error if called after prerender aborts (#96426)
Closes #96339

Caches that started filling after a prerender was aborted would produce
an empty stream, because an aborted `renderSignal` made [the signal we
pass to `prerender()` inside `use-cache-wrapper`] be aborted
immediately. So we produced an empty entry and saved it, essentially
poisoning the cache.

Fixed by removing `renderSignal` from the `AbortSignal.any(...)` we pass
in and returning a rejected promise before we get to the cache filling
codepath. This should not be observable to userspace because the
prerender is already aborted.
2026-08-03 11:42:26 +00:00
next-js-bot[bot] 4fd843fb48 v16.3.0-canary.107 v16.3.0-canary.107 2026-08-02 23:34:28 +00:00
Tim Neutkens 3d4d46f1c9 Enable Turbopack build filesystem cache by default (#96493)
## Summary

Enable `experimental.turbopackFileSystemCacheForBuild` by default in all
environments, including generic CI. Explicitly setting the option to
`false` remains the opt-out. Update the focused coverage and
documentation to match.

## Verification

- `IS_TURBOPACK_TEST=1 pnpm test-start-turbo
test/e2e/filesystem-cache/build-cache-default.test.ts`
- `pnpm prettier --with-node-modules --ignore-path .prettierignore
--check packages/next/src/server/config-shared.ts
test/e2e/filesystem-cache/build-cache-default.test.ts
docs/01-app/03-api-reference/08-turbopack.mdx
docs/01-app/03-api-reference/05-config/01-next-config-js/turbopackFileSystemCache.mdx`
- Not run: `pnpm --filter=next build` (the checkout has 11 pre-existing
TypeScript errors in unrelated files)

<!-- NEXT_JS_LLM -->
2026-08-02 11:33:33 -07:00
next-js-bot[bot] 9480f7f9ff v16.3.0-canary.106 v16.3.0-canary.106 2026-08-01 23:33:55 +00:00
Hendrik Liebau ccd47cfe53 Warn that experimental.useCache is deprecated (#96448) 2026-07-31 20:26:10 -04:00
Zack Tanner 893121b887 Fix hybrid Pages/App Router not-found rendering with adapters (#96392)
## Summary

When Pages Router and App Router routes coexist, a Pages Router route
that returns `notFound` will internally hand rendering to the App Router
not-found page. Next.js [prefers the App Router `/_not-found` entry for
404
responses](https://github.com/vercel/next.js/blob/5f5e4773bbb54f19697063ea093e8d89ca7d081a/packages/next/src/server/base-server.ts#L2965-L2980)
before falling back to a Pages Router `/404` page.

When deployed via an adapter, this means it would have attempted to
resume the Pages entry, which wouldn't contain the relevant prerendered
shell or postponed state. If the not-found page suspends, its response
cannot be resumed using the metadata associated with the Pages Router
output.

For adapter requests, this marks the handoff with an empty postponed
state. This uses the existing resume protocol to perform a complete,
non-cacheable dynamic render. `next start` continues to use the normal
PPR path, where it can load and resume the App Router not-found output
directly.

This trades PPR shell reuse for correctness only during this
cross-router not-found handoff. Longer term, adapters should have an
explicit contract for cross-output handoffs so they can select and
resume the App Router not-found output normally, without necessarily
declaring the pages router output PPR-capable.

The change also documents the empty postponed-state contract and adds
deployment regression coverage.

## Verification

- Added an end-to-end test that verifies a Pages Router `notFound`
response includes the dynamic App Router not-found content when
deployed.
- `pnpm testheadless test/e2e/app-dir/pages-router-app-not-found`
- `pnpm --filter=next types`

<!-- NEXT_JS_LLM -->
2026-07-31 16:40:37 -07:00