Commit Graph

22 Commits

Author SHA1 Message Date
Josh Story d424aa8ec4 Stabilize unstable_instant (#94578)
This API has experimental modes for build validation but the dev
validation is going to be stable in the next release.
2026-06-09 13:50:25 -07:00
Vercel Release Bot 84f9247617 Upgrade React from f0dfee38-20260529 to 43bcbf80-20260603 (#94440)
[diff
facebook/react@f0dfee38...43bcbf80](https://github.com/facebook/react/compare/f0dfee38...43bcbf80)

<details>
<summary>React upstream changes</summary>

- https://github.com/facebook/react/pull/36586
- https://github.com/facebook/react/pull/36603
- https://github.com/facebook/react/pull/36585
- https://github.com/facebook/react/pull/36580
- https://github.com/facebook/react/pull/36584
- https://github.com/facebook/react/pull/36583
- https://github.com/facebook/react/pull/36576
- https://github.com/facebook/react/pull/36575
- https://github.com/facebook/react/pull/36574

</details>

---------

Co-authored-by: next-js-bot[bot] <279046576+next-js-bot[bot]@users.noreply.github.com>
Co-authored-by: Josh Story <gnoff@storyposted.com>
2026-06-05 08:11:55 -07:00
Sebastian "Sebbie" Silbermann 7644b7e509 Ensure aborting has the same inputs as render (#94436) 2026-06-03 22:20:23 +00:00
Aurora Scharff a0c6a6140e instant: enable navigation validation by default (#94312)
### What?

Flips the default `experimental.instantInsights.validationLevel` from
`'manual-warning'` to `'warning'` so Cache Components apps get
instant-navigation validation across all pages by default.

### Why?

`'manual-warning'` only validates pages that explicitly export
`unstable_instant`, so apps see nothing unless they opt in. `'warning'`
is what users have been turning on manually to actually see the feature
(`v0`, `vercel-site`).

### Test coverage

- Unit: `instant-config-normalization.test.ts` pins the framework
default at `'warning'`.
- Integration: new `instant-validation-level-default/` fixture (no
`instantInsights` in config) asserts implicit dev validation fires, and
that build is unaffected.

### Collateral test fixtures

Tests whose intent is unrelated to instant validation
(router-autoscroll, owner-stack, hmr-iframe, next-image,
server-source-maps, etc.) now hit new redboxes/console warnings because
their fixtures incidentally use dynamic data. Each opts out with
`experimental: { instantInsights: { validationLevel: 'manual-warning' }
}` in `next.config`.

### Open question

With no `'off'` / `'info'` tier today, silencing Insights after this
change requires setting `validationLevel: 'manual-warning'`. Is that
acceptable? Should we inform of this anywhere?

<!-- NEXT_JS_LLM_PR -->
2026-06-03 01:26:11 +02:00
Hendrik Liebau 3cf7aa2473 Honor Suspense-above-body opt-in for dynamic generateViewport (#93759) 2026-05-12 15:43:34 +02:00
Hendrik Liebau 6541ab5be8 Improve error stacks for dynamic API usage in "use cache" (#92736)
When `cookies()`, `headers()`, `draftMode()`, or `connection()` are
called inside `"use cache"` from third-party (ignore-listed) code, the
error stacks previously had no usable frames. The redbox showed no
source location and an empty call stack, and the build output only
showed `at ignore-listed frames`. This made it difficult to trace which
component was responsible for the invalid API usage.

This PR fixes the issue by calling React's `captureOwnerStack()` at the
`"use cache"` boundary (in `use-cache-wrapper.ts`) before entering the
cache scope, and storing the result on the cache work unit store as
`outerOwnerStack`. When an error is later thrown inside the cache scope
(e.g. from `cookies()`), `applyOwnerStack()` concatenates the inner
owner stack (from within the cache scope) with the stored outer owner
stack to reconstruct the full component tree across cache boundaries.
This also correctly handles nested `"use cache"` scopes by chaining the
outer owner stacks.

The `applyOwnerStack` function was extracted from `io-utils.tsx` into
`dynamic-rendering-utils.ts` so it can be reused by both the request API
files (`cookies.ts`, `headers.ts`, `draft-mode.ts`, `connection.ts`) and
the sync IO error handling in `io-utils.tsx`.

New test cases cover both first-party and third-party usage of all four
APIs, including a previously missing `connection()` in `"use cache"`
test case.
2026-04-14 12:25:04 +02:00
Hendrik Liebau 469e513c5f Require explicit cacheLife on outer "use cache" when nesting short-lived caches (#89481)
This PR adds error handling for nested `"use cache"` where the inner
cache has a very short lifetime (zero `revalidate` or `expire` under 5
minutes) but the outer cache doesn't have an explicit `cacheLife()`
call.

Short-lived caches become "dynamic holes" that are excluded from
prerenders. When such a cache is nested inside another `"use cache"`
without an explicit `cacheLife`, the outer cache's lifetime would
silently become short too via
[propagation](https://nextjs.org/docs/app/api-reference/functions/cacheLife#nested-caching-behavior),
which can lead to unexpected behavior. To prevent this accidental
misconfiguration, Next.js now throws an error during prerendering,
requiring developers to explicitly declare their intent by adding
`cacheLife()` to the outer cache.

The implementation tracks whether `revalidate` and `expire` were
explicitly set via `hasExplicitRevalidate` and `hasExplicitExpire` flags
on the collected cache result. Errors are wrapped with
`wrapAsInvalidDynamicUsageError` to capture proper stack traces and
prevent userland try/catch from suppressing the build error.

Documentation has been updated with a new "Prerendering behavior"
section in the `cacheLife` API reference explaining how short-lived
caches become dynamic holes, and a "Nested short-lived caches"
subsection with examples showing how to fix the error.

closes NAR-761
2026-02-05 15:39:08 +00:00
Sebastian "Sebbie" Silbermann a77fd58c96 Upgrade React from bef88f7c-20260116 to 41b3e9a6-20260119 (#88756)
Co-authored-by: nextjs-bot <it+nextjs-bot@vercel.com>
2026-01-19 21:44:49 +01:00
Janka Uryga 5d7c41a47d [Cache Components] Ensure cache misses always cause a restart in dev (#86583)
This PR works around a problem in the restart-on-cache-miss rendering
flow where short-lived caches wouldn't be considered dynamic if they
managed to fill microtaskily.

The problem is that:

1. If a cache fills microtaskily, it won't register as a cache miss, so
we won't restart the render
2. The logic for omitting short-lived caches only runs for cache hits
(because it expects to run in the final render), so it won't be applied
to a cache we just filled

The fix implemented here isn't ideal, but fixes the problem -- we just
make it so that all caches take at least a task to fill, and thus all
cache misses will be "noticed" and cause a restart.

This sacrifices the nice property we had before where a microtasky cache
miss wouldn't trigger a restart, but we can live with that for now for
the sake of correctness.
2025-11-28 13:41:49 +01:00
Hendrik Liebau 3b8cd9225b Fix error logging for 'use cache' runtime errors in production (#86500)
In production, when throwing an error in `'use cache'` at runtime, we
are currently logging the obfuscated error that React is producing when
crossing the cache-server boundary. This is not ideal for investigating
production issues so we're also logging the original error in the `'use
cache'` wrapper as a work-around. But this error does not have a digest,
which makes it non-obvious that it's the same error as the obfuscated
one.

With this PR we are fixing this by storing the original error (with a
digest) in the `reactServerErrorsByDigest` map (moved to the work
store), and retrieving it in the server environment when we log the
error. Thus the obfuscated error is not logged, and the original error
with a digest is logged instead.

In development, we keep the existing behavior of logging the transported
error, which also includes the dev-only `environmentName` property
`'Cache'`.

As part of this fix, we're consolidating the
`createFlightReactServerErrorHandler` and
`createHTMLReactServerErrorHandler` functions, which had a big overlap
and confusing names, into a single `createReactServerErrorHandler`
function.

closes NAR-536
2025-11-27 20:25:32 +01:00
Hendrik Liebau f71ce534a8 [test] Add test fixture for runtime error in 'use cache' (#86499)
In production, when throwing an error in `'use cache'` at runtime, we are currently logging the obfuscated error that React is producing when crossing the cache-server boundary. This is not ideal for investigating production issues so we're also logging the original error in the `'use cache'` wrapper. But this error does not have a digest, which makes it non-obvious that it's the same error as the obfuscated one.

This PR is just adding a test fixture for this case, so that we can see the changes when improving the error handling in the upstack PR.
2025-11-26 16:00:35 +01:00
Janka Uryga 3f4db01dbc [Cache Components] Discriminate static shell validation errors by type (#85747)
Prior to this change any "hole" in a prerender that would block the
shell was considered an error and you would be presented with a very
generic message explaining all the different ways you could have failed
this validation check.

With this change we use a new technique to validate the static shell
which can now tell the difference between waiting on uncached data or
runtime data. It also improves the heuristics around generateMetadata
and generateViewport errors.

Added new error pages for runtime sync IO and ensure we only validate
sync IO after runtime data if the page will be validating runtime
prefetches.

Restored the validation on HMR update so you can get feedback after
saving a new file.

---

We've also discovered that hanging inputs are not handled correctly.
Fixing this is non-trivial and will be done in a follow-up, so for now,
we're disabling the failing tests.

---------

Co-authored-by: Josh Story <story@hey.com>
Co-authored-by: Hendrik Liebau <mail@hendrik-liebau.de>
2025-11-20 17:13:37 +01:00
Hendrik Liebau 1558dbefc2 [test] Add test cases for dynamic caches without suspense boundaries (#85500)
When defining a `cacheLife` with an expire time below 5 minutes or a
revalidate time of 0 we consider the `'use cache'` function dynamic
during prerendering, i.e. it will be excluded from the static shell.
Similarly, accessing runtime `params` (not defined in
`generateStaticParams`) also makes the function dynamic. Those cases
require adding a parent suspense boundary. If there's no suspense
boundary, we should show an error during prerendering at build time, as
well as in development as part of the prerender validation. The latter
is currently not working as expected when the `'use cache'` directive is
used in a page (or layout) directly. As the added snapshot tests show,
no redbox is shown in those cases. This is a known issue that we plan to
address separately.

We will also follow up with improving the error messages and docs for
those dynamic cache cases. This detail got lost in #85087.
2025-10-29 13:34:26 +01:00
Zack Tanner 85c3d20a91 [cache components]: move flag out of experimental (#85035)
This moves `experimental.cacheComponents` to a top level config. As part
of this, I disabled some tests in `build-output-prerender` that assert
on `cacheComponents` appearing in the experimental list. In a separate
PR, I'm going to show that Cache Components is enabled next to the
bundler info.

This also updates some docs pages to remove "experimental" language.
2025-10-18 14:13:44 -07:00
Janka Uryga b7b153f623 [Cache Components] Fix cacheSignal in dev render (#84846)
This PR changes the timing used in `CacheSignal.cacheReady()` to work
correctly when rendering, not just prerendering. When rendering, React
schedules new work in `setImmediate` (as opposed to using a microtask
when prerendering), and `CacheSignal.cacheReady()` needs to account for
that, because we need to wait longer to make sure that react had time to
render and thus we've started all the relevant cache reads.

Note that this PR increases the delay for both prerender _and_ render.
This is to make it easier to reason about (by not having separate
codepaths), but also to not be so tightly coupled to React pinging work
in a microtask when prerendering, in case that changes in the future.
2025-10-15 18:32:43 +02:00
Jiwon Choi 1dda5b668b [Breaking] Remove deprecated sync access to Dynamic APIs (#84179)
This PR removes the deprecated sync access to Dynamic APIs.

- Removed UnsafeUnwrapped* types.
- Replaced `as unknown as UnsafeUnwrapped ` type casts to `as any` for
dev warning.
- Removed tests that expected sync access to not error.
- Removed `UntrackedExotic` functions.
- Modified tests that were accidentally doing sync access.
- Updated warnings to emphasize that it is a Promise and must be
awaited.
- Removed paragraph that states access is allowed from
`errors/sync-dynamic-apis.mdx`.

---------

Co-authored-by: Josh Story <story@hey.com>
2025-09-27 22:44:45 +02:00
Janka Uryga ad7c7563db [Cache Components] allow using headers() in runtime prefetches (#83838)
This PR allows usage of `headers()` in runtime prefetches and private
caches. The implementation is basically analogous to `cookies()`.

Closes NAR-353
2025-09-22 17:31:10 +00:00
Josh Story c5dab31407 Ignore unhandledRejection events for promises that reject after a React render aborts (#83590)
Currently we only abort React renders that are prerendered so this
change in practice only affects prerendering. The intent is to not
report unhandledRejections that are downstream of an abort because the
signal these errors provide is very limited. If you do have unrelated
unhandled rejections they'll usually show up before aborting or in a
dynamic page render so even if they are incidentally supressed in the
prerender context you should still be able to observe them.

Arguably we should go further and never report unhandled rejections
because there are still valid patterns where you initiate work
prospectively and then abandon it by choosing a fork or by returning
early (i.e. notFound()). This change doesn't attempt to cover every
possible case.

The implementation is a bit intense. We need the ability to stop
propagating the event which is not natively supported with Node's
EventEmitter interface. Instead we patch the listener methods to
delegate the filtering to an inner listener queue. If you add/remove or
otherwise manipulate the listener list we always ensure our listener is
first and can opt to omit propagating the event. If you want to
uninstall the this patch you just need to unregister this listener
specifically which can be accessing used
`process.listeners('unhandledRejection')[0]`

This patch only exists for the node environment because we do not do any
prerendering in edge runtimes. In the future if we add aborting to
environments like edge runtime we may need an alternative solution to
this problem
2025-09-09 20:46:31 -07:00
Josh Story ed5d085fb1 [Cache Components] Error for Sync IO in Server Components during Static Prerender (#82500)
Currently we error if you cannot produce a shell unless you have a
Suspense boundary above the root. This is fine for normal IO but sync IO
like Math.random() and new Date() have much more significant bad
consequences for prerendering. Instead of treating these errors as
another flavor of "must have a shell" validation we should instead treat
them like they must be guarded behind something else dynamic like `await
connection()`.

In addition to unconditionally erroring for Sync IO in Server Components
when prerendering this change also removes the Sync IO warning for
runtime prefetches. This is because at the moment there is no way to
debug these errors in dev. In the future we will add validation for
prefetches and need to add back in some ability to warn for these cases
but until then we will leave this case as a silent deopt.
2025-08-20 15:23:31 +00:00
Hendrik Liebau 662918f9a2 [Cache Components] Disallow sync access of cookies & headers at runtime (#82564)
In #81162 we removed the support for accessing request data
synchronously when `experimental.cacheComponents` is enabled. However,
we missed updating the `cookies()` and `headers()` promises that are
created at runtime to not be "exotic" promises, i.e. promises that also
have the cookies/headers methods defined on them. Those two cases are
now updated as well with this PR. (Params, search params, and draft mode
were already handled correctly in the original PR.)

In the next major version we'll remove the support for the legacy
synchronous access independent of the `cacheComponents` flag.
2025-08-13 19:08:12 +02:00
Hendrik Liebau 9dc2d46954 Introduce 'use cache: private' (#81816) 2025-07-21 21:07:01 +02:00
Wyatt Johnson 8abbb3dc2e refactor: rename experimental.dynamicIO to experimental.cacheComponents (#81562)
## What?

Rename `experimental.dynamicIO` to `experimental.cacheComponents` across
the Next.js codebase.

## Why?

We're going to be merging the functionality of the `ppr`, `dynamicIO`
and `useCache` experimental flags into the singular `cacheComponents`
flag to reduce complexity of the codebase and simplify adoption for
users wanting to experiment with experimental features.

## How?

- Renamed the configuration option from `experimental.dynamicIO` to
`experimental.cacheComponents`
- Added deprecation handling with automatic migration for the old option
name
- Updated all documentation, tests, and internal references
- Updated Rust code in SWC transforms and Turbopack
- Maintained backward compatibility with deprecation warnings

NAR-158
2025-07-17 19:30:28 -06:00