35 Commits

Author SHA1 Message Date
dan f2ce9d4bfd [test] Run the navigation e2e suite under cacheComponents (#95877)
This test suite used to be disabled in CC runs, which feels like a bit
of a hazard for developing CC.

Let's enable it.
2026-07-27 20:54:10 +01:00
dan 2dea98ed31 [test] Run more test suites under cacheComponents flag, again (#96196)
Reverts the revert of #95878.

This failed on `main` due to React bugs
(https://github.com/react/react/pull/37061?) which are fixed now.
2026-07-27 20:54:09 +01:00
Hendrik Liebau c3d5b92778 [test] Move the dev-only use cache test suite to test/development (#96023)
The `use-cache-dev` suite only covers dev-mode HMR behavior of `use
cache`, so it belongs under `test/development/app-dir` alongside the
other `cache-components-dev-*` suites rather than in `test/e2e`. Because
`test/development` runs only in dev mode and is never deployed, the
production-mode placeholder guard, the `skipDeployment` option, and the
`if (skipped)` early return are all dropped. The three test manifests
that referenced the old path are updated.


---

<sub>Stack created with <a
href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a
href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>
2026-07-22 15:50:22 +02:00
Sebastian "Sebbie" Silbermann ce207309be [test] Add coverage for throwing custom "use cache" cache handler (#95984)
This is relevant if the cache is in a broken state or the keys or
entries are not suitable (e.g. an entry that's to large to be stored).

Revealed several oddities:
1. cache handler have no no sources content (not too bad since that
means the codeframe points into the problem `use cache` function which
is usually the cause)
2. A throwing `set` is swallowed in dev
3. A throwing `get` is logged as a caught error and an unhandled
rejection. This is spammy.
2026-07-21 10:23:54 +02:00
dan e75d082512 Revert "Run more test suites under cacheComponents flag" (#95884)
Reverts vercel/next.js#95878

Don't understand the failure after merging into canary yet, let's revert
to unblock CI
2026-07-17 00:33:26 +00:00
dan 6e558b1790 Run more test suites under cacheComponents flag (#95878)
Similar to https://github.com/vercel/next.js/pull/95877.

Some of these need loading boundaries so that CC doesn't complain about
being blocking.
2026-07-16 22:53:53 +01:00
dan 40b0e3d848 Preserve init errors from async route modules (#95799)
Extracted from https://github.com/vercel/next.js/pull/95468.

We did not have error handling around async module initialization. As a
result, in `output: 'export'` mode, an error during async initialization
were reported as unhandled rejections. Now it properly fails the build.
2026-07-15 10:49:06 +01:00
Benjamin Woodruff a87692e17c [ci] Split up large rsc-build-errors development test (#95624)
See https://github.com/vercel/next.js/pull/95553 for an explanation of
why we want to split these up. TL;DR it makes CI faster and saves us
some money.

In CI we have to run tests at the suite/file granularity, so if a test
suite is too long it limits parallelism and if it has to be retried, we
have to retry the full suite.
2026-07-08 19:56:27 -07:00
Hendrik Liebau c845bafd6c Enforce route segment configs on metadata routes under Cache Components (#94962)
The React Server Components transform validates route segment configs
(rejecting `runtime`, `dynamic`, `revalidate`, and friends under Cache
Components) only for `page`, `layout`, and `route` entries, so metadata
convention files slipped past the check. Because these files compile to
route handlers and accept the same configs, this change extends the
match to `icon`, `apple-icon`, `opengraph-image`, `twitter-image`,
`sitemap`, `robots`, and `manifest`. Exporting `runtime = 'edge'` (or
any other unsupported config) from one of them is now a compile-time
error that matches the behavior for regular routes, instead of surfacing
later as a confusing bundling failure. The `metadata-font` suite, which
intentionally builds edge-runtime image routes, joins the other edge
metadata suites that are excluded from the Cache Components test run.
2026-06-19 18:40:36 +02:00
Jude Gao 1cad9e989a Rename experimental.useExperimentalReact to blockingSSR (#94869)
`experimental.useExperimentalReact` names the React *build* it pulls in
rather than the feature it's there for. Rename it to `blockingSSR` — the
actual capability (React's blocking SSR, which emits `<link
rel="expect">` to hold first paint until the streamed shell is coherent)
— mirroring React's own feature flag so it's clear why the experimental
channel got enabled when grepping.

<!-- NEXT_JS_LLM_PR -->
2026-06-17 10:35:07 -04:00
Jude Gao 71b70e01b8 Add experimental.useExperimentalReact to opt into React's experimental channel (#94861)
Opting into React's experimental channel — which emits `<link
rel="expect">` to hold first paint until the streamed shell is coherent,
avoiding flicker from partially-streamed HTML — currently requires
enabling an unrelated feature like `experimental.taint` as a side
effect, which is confusing. This adds
`experimental.useExperimentalReact` as a direct opt-in.

It feeds the existing `needsExperimentalReact` aggregation and the
matching Turbopack `react_channel` switch, selecting the
`react@experimental` build the same way `taint`, `transitionIndicator`,
and `gestureTransition` do. It's opt-in only: an explicit `false` can't
disable the channel when one of those still requires it (the taint APIs
only exist in the experimental build), so `assignDefaults` warns on that
contradiction. Covered by a webpack e2e test mirroring the existing
`taint` channel test.

<!-- NEXT_JS_LLM_PR -->
2026-06-16 15:08:47 -04:00
Hendrik Liebau 2ca0d5df1c [test] split og-api test suite into default and standalone variants (#93915)
The fixture's `next.config.js` had `output: 'standalone'` hardcoded,
which is meaningless on Vercel deployments (the standalone directory is
ignored) but became a build-time crash after #93684 made the Turbopack
NFT generator skip `next-server.js.nft.json` whenever an adapter is
configured. With `output: 'standalone'` still active,
`writeStandaloneDirectory` then fails with `ENOENT` when it tries to
read that file
([x-ref](https://github.com/vercel/next.js/actions/runs/26006483168/job/76441905221)).

This PR splits the `og-api` E2E suite into a default variant and a
`standalone.test.ts` wrapper that enables `output: 'standalone'` via the
`TEST_OUTPUT_STANDALONE` env var, and excludes the standalone wrapper
from the deploy test manifest.

The default variant still runs in `deploy` mode and preserves coverage
of `next/og` from Pages Router API routes, App Router route handlers
(edge and node), and middleware — paths not covered by the metadata-*
fixtures. The standalone variant continues to exercise the trace-copy
assertion in `next start` mode.

---------

Co-authored-by: Tim Neutkens <tim@timneutkens.nl>
2026-05-18 12:14:43 +00:00
Tim Neutkens 8141dcf12e Convert test/integration to isolated tests (#93247)
### What?

Converts every test under `test/integration/` to an isolated test
running through `nextTestSetup` (under `test/e2e/`, `test/production/`,
`test/development/`, or `test/unit/`), then deletes `test/integration/`
along with the legacy CI orchestration that was specific to it.

- `test/integration/` removed entirely (~327 test suites)
- New isolated suites added across the existing folders:
  - `test/e2e/` — 175
  - `test/production/` — 130
  - `test/development/` — 43
  - `test/unit/` — 1
- `.github/workflows/build_and_test.yml` and `run-tests.js` no longer
have any `integration` branches
- `nextTestSetup` gained a `baseUrl` option on `next.browser()` so a
small number of tests that drive their own proxy/static-export server
can keep using `next.browser(...)` instead of importing `next-webdriver`
directly

### Why?

`test/integration/` predated `nextTestSetup` and ran tests directly
against the source checkout via custom helpers (`launchApp`,
`nextBuild`, `nextStart`, `runNextCommand`, `webdriver`, `fetchViaHTTP`,
…). Each suite hand-rolled its own dev/start/build orchestration,
fixture mutation, and process management.

The isolated test model used by the rest of the repo gives each suite an
isolated working directory containing a packed `next.tgz` install, a
uniform `next.start()` / `next.build()` / `next.fetch()` /
`next.browser()` API, and the same lifecycle for dev, start, and deploy
modes — so a single set of assertions covers all three. Deploy-mode
skips and per-feature gates are expressed declaratively
(`skipDeployment`, `disableAutoSkewProtection`, `if (skipped) return`)
instead of branching on `process.env`.

Removing `test/integration/` lets us:

- Delete the bespoke orchestration code in the CI workflow and
`run-tests.js`
- Run every converted suite consistently in dev, start, and deploy modes
(where applicable)
- Reproduce every test locally with the same `pnpm
test-{dev,start}-{turbo,webpack}` commands; no separate `integration`
path
- Open the door to running `test/production` against deployments in the
future (the converted suites already declare `skipDeployment` so they
can be flipped on)

### How?

Mechanical conversion per suite, with targeted clean-ups:

1. **Per-suite conversion.** Each
`test/integration/<name>/test/index.test.{js,ts}` was rewritten into a
single `<name>.test.ts` under the right folder based on what the
original exercised:
   - `launchApp` / dev-only assertions → `test/development/`
- `nextBuild` + `nextStart` / start-only assertions → `test/production/`
   - Both → `test/e2e/`
- The one pure jsdom render check (`link-without-router`) → `test/unit/`

2. **API mapping.** Custom helpers were replaced by `nextTestSetup`
equivalents: `launchApp` → `next.start()`, `nextBuild` → `next.build()`,
`runNextCommand` → `next.runCommand`, `fetchViaHTTP` → `next.fetch`,
`webdriver(...)` → `next.browser(...)`. Fixture mutations switched from
raw `fs.writeFile`/`fs.rename` to `next.patchFile` (with the 3-arg
`runWithTempContent` callback when the change has a defined scope) and
`next.deleteFile`.

3. **Deploy-mode handling.** Suites that can't run in deploy mode (use
`patchFile` / `next.build()` / depend on local CLI output) declare
`skipDeployment: true` and early-return on the `skipped` boolean. Suites
where Vercel's edge mutates URLs (`&dpl=`, immutable assets) declare
`disableAutoSkewProtection: true`.

4. **`next.browser({ baseUrl })`.** A handful of tests
(`prerender-export`, `cdn-cache-busting`, `preload-viewport`, both
`react-virtualized` suites) need to drive a separate server (a
static-export server or an `http-proxy` instance) rather than the
Next.js process. Instead of importing `next-webdriver` directly, those
tests now pass `{ baseUrl: <port|url> }` to `next.browser()`. For the
proxy cases, the proxy was moved into `server.js` inside the fixture and
`http-proxy` declared via the `dependencies` option of `nextTestSetup`,
so the test runs with a fully isolated dependency graph.

5. **CI clean-up.** With `test/integration` gone, the `test
integration*` jobs and `integration-tests-manifest`-related logic in
`.github/workflows/build_and_test.yml` were removed, and `run-tests.js`
no longer has the `integration` test-folder branch.

6. **Validation.** The PR was iterated against multiple full CI runs;
the remaining failures on the latest run are pre-existing flakes
(segment-cache 60s `act` timeouts in turbopack-prod) or transient
infrastructure issues unrelated to the conversion.
2026-05-11 13:55:47 +02:00
Josh Story 766b7cbff4 Stabilize unstable_io (#93621)
Removes the unstable prefix from `unstable_io`. Since this was only
shipped in canaries with the unstable prefix we are going to just remove
it without retaining the unstable prefix simultaneously.
2026-05-07 16:39:37 -07:00
Tim Neutkens 84f1e44d4d Deprecate edge runtime (#93369)
Note: re-apply of #92817

### What?

Deprecates the Edge Runtime and the `preferredRegion` route segment
config that only applied to edge runtime with build-time warnings,
TypeScript IDE hints, error documentation pages, and documentation
updates.

### Why?

Edge Runtime in Next.js is being deprecated in favor of the Node.js
runtime (the default). The `preferredRegion` route segment config is
tightly coupled to Edge Runtime and is also being deprecated.

### How?

**Edge Runtime deprecation:**
- Added `warnAboutEdgeRuntime()` helper using `Log.warnOnce` in
`packages/next/src/build/warn-about-edge-runtime.ts`
- Warning fires in `get-page-static-info.ts` (Webpack dev/build +
Turbopack build) and `turbopack-utils.ts` (Turbopack dev) when `runtime
= 'edge'` is detected
- Marked `'edge'` as `@deprecated` in the TypeScript language service
plugin (`rules/config.ts`)
- Created `errors/edge-runtime-deprecated.mdx` with migration guidance
- Updated documentation across 11 files to add deprecation notices or
simplify/remove outdated Edge Runtime references

**`preferredRegion` deprecation:**
- Added `warnAboutPreferredRegion()` helper in the same file
- Warning fires in `get-page-static-info.ts` for both App Router
(`config.preferredRegion`) and Pages Router (`config.config?.regions`)
- Marked `preferredRegion` as `@deprecated` in the TypeScript language
service plugin and the generated types (`next-types-plugin`)
- Created `errors/preferred-region-deprecated.mdx` with migration
guidance (remove the export)
- Updated documentation across 4 files to add deprecation notices

**Tests:**
- Added `test/e2e/edge-runtime-deprecated/` with fixture and assertions
for the edge runtime warning (dev + production)
- Added `test/production/preferred-region-deprecated/` with fixture and
assertions for the preferredRegion warning (production only -- Turbopack
dev does not surface `preferredRegion` from the Rust layer to JS)

<!-- NEXT_JS_LLM_PR -->

---------

Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
2026-04-30 10:01:06 +02:00
Hendrik Liebau 8e4cfc5062 Honor the route-level expire value with blocking revalidation (#93211)
A prerendered route's `expire` — set via `cacheLife({ expire })` inside
`'use cache'` or via the `expireTime` config fallback — lands in the
prerender manifest as `initialExpireSeconds` / `fallbackExpire`
(#76207), but the runtime never read it: `IncrementalCache.get` only
considered `revalidate`. So past expire, Next.js served stale with a
background refresh instead of the blocking regeneration the `cacheLife`
`expire` docs describe.

The fix is three coordinated changes. The render-time
`responseGenerator` in `app-page.ts`, `app-route.ts`, and
`pages-handler.ts` now applies the `expireTime` fallback as soon as it
has the render's `cacheControl`, so every downstream consumer (the cache
stored via `IncrementalCache.set`, the response `Cache-Control` header,
the entry returned to `handleResponse`) sees a finalized `cacheControl`
with a populated `expire` — mirroring the build-time fallback.
`IncrementalCache.get` then returns `isStale = -1` when `lastModified +
expire * 1000 < now`, and `response-cache.handleGet` skips its early
`resolve(previousEntry)` for `isStale === -1` so the blocking
revalidation inside `responseGenerator` (which already picks
`BLOCKING_STATIC_RENDER` on that signal) can return its fresh output to
the user. Previously the early resolve committed the stale value to the
response first, so even though `responseGenerator` still ran a fresh
render its output only warmed the cache for the next request. As a side
effect this also closes the same early-resolve hole on the existing
tag-expired `isStale = -1` path.

On Vercel, ISR cache decisions live at the Proxy and the Proxy currently
ignores `staleExpiration` (using a hard-coded one-year value instead).
It is also expected, once it starts honoring `staleExpiration`, to pick
up updated values from the `stale-while-revalidate` response header.
Until that lands this change is only observable on `next start` —
deploy-mode behavior is tracked independently of Next.js.

Two test suites cover the new behavior.
`test/production/app-dir/use-cache-expire` uses `cacheComponents` +
`cacheLife({ expire: 300 })` with a custom cache handler that shifts
`lastModified` via an `x-test-cache-age-offset-ms` header, exercising
the fully-static shell, the partially-static route shell for a known
param, and the partially-static fallback shell for unknown params.
`test/e2e/app-dir/expire-time` covers classic ISR (`revalidate = 1`,
`expireTime: 2`) with a real three-second wait and is `it.failing` on
deploy, so it will flip the moment the Proxy honors the expire value.

fixes #78269
2026-04-29 08:20:37 +00:00
Josh Story e22dc27d8f Add experimental unstable_io() API behind experimental.unstableIO flag (#92521)
Adds a new export from next/cache that acts as a metasyntactic IO
boundary. During prerendering with cache components it returns a hanging
promise to prevent execution of code that follows it. In all other
contexts it resolves as a fulfilled thenable that React can unwrap
synchronously. This is gated behind experimental.unstableIO and not
ready for general use.
2026-04-08 13:09:53 -07:00
Tim Neutkens 4582b5fa93 Reapply "ci: add node-stream test coverage workflow (#89861)" (#91664)
Re-apply #89861.

Somehow the tests passed in the PR but failed after merging. Will dig
into it.

Edit: Dug into it, there was a missing env var. Fixed and ready to merge
now.

PR doesn't add the Node.js streams code path. Implementation starts in
#90500
2026-04-01 20:42:25 +02:00
Sebastian "Sebbie" Silbermann ba01f6578c [test] Enable scroll related tests in Cache Component tests (#83245) 2026-02-11 16:20:08 +01:00
Hendrik Liebau 5ec4d7a4be [Cache Components] Prevent streaming fetch calls from hanging in dev (#89171)
With Cache Components enabled in development, fetches without an
explicit cache config were incorrectly routed through
`createCachedPrerenderResponse` during the cache filling phase due to
the `serverComponentsHmrCache` condition. This function awaits the
entire response before returning to the caller, which prevents
infinitely streaming responses from ever being read or aborted.

This is a regression that was introduced in #84088.

These fetches should be treated as dynamic and use
`createCachedDynamicResponse` instead, which returns immediately and
caches in the background with proper error handling. The fix adds
`isCacheableRevalidate` to the condition so only explicitly cacheable
fetches use the blocking path.

Additionally, the "Failed to set fetch cache" warning is now suppressed
when the request's abort signal was triggered, since aborting is
intentional.
2026-01-28 21:53:56 +01:00
Niklas Mischkulnig 0683859c93 Migrate app-dir-export test to be isolated (#86534)
Flakey:
```
❌ test/integration/app-dir-export/test/start.test.ts output:
HEADLESS=true NEXT_TELEMETRY_DISABLED=1 CI= NEXT_TEST_CI=true IS_RETRY=undefined TRACE_PLAYWRIGHT=true CIRCLECI= GITHUB_ACTIONS= CONTINUOUS_INTEGRATION= RUN_ID= BUILD_NUMBER= JEST_JUNIT_OUTPUT_NAME=test_integration_app-dir-export_test_start.test.ts JEST_SUITE_NAME=default:12/13:integration:test/integration/app-dir-export/test/start.test.ts /root/actions-runner/_work/next.js/next.js/node_modules/.bin/jest '--ci' '--runInBand' '--forceExit' '--verbose' '--json' '--outputFile=test/integration/app-dir-export/test/start.test.ts.results.json' 'test/integration/app-dir-export/test/start.test.ts'
[08:48:33.323Z] Running command "next build /root/actions-runner/_work/next.js/next.js/test/integration/app-dir-export"
▲ Next.js 16.1.0-canary.1
- Local:         http://[::1]:36371
- Network:       http://[::]:36371

✓ Starting...
Error: "next start" does not work with "output: export" configuration. Use "npx serve@latest out" instead.
    at <unknown> (dist/server/next.js:230:53)
    at async NextServer.prepare (dist/server/next.js:177:24)
    at async initializeImpl (dist/server/lib/render-server.js:132:5)
    at async initialize (dist/server/lib/router-server.js:538:22)
    at async Server.<anonymous> (dist/server/lib/start-server.js:381:36)
[08:49:12.558Z] Running command "next build /root/actions-runner/_work/next.js/next.js/test/integration/app-dir-export"
FAIL webpack test/integration/app-dir-export/test/start.test.ts (100.119 s)
  app dir - with output export (next start)
    production mode
      ✓ should error during next start with output export (39235 ms)
      ✕ should warn during next start with output standalone (60029 ms)

  ● app dir - with output export (next start) › production mode › should warn during next start with output standalone

    thrown: "Exceeded timeout of 60000 ms for a test.
    Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."

      46 |
      47 |       // TODO: Move this test to test/production to run in isolation.
    > 48 |       ;(process.env.TURBOPACK_BUILD ? it.skip : it)(
         |                                                  ^
      49 |         'should warn during next start with output standalone',
      50 |         async () => {
      51 |           nextConfig.replace(`output: 'export'`, `output: 'standalone'`)

      at integration/app-dir-export/test/start.test.ts:48:50
      at integration/app-dir-export/test/start.test.ts:21:56
      at Object.describe (integration/app-dir-export/test/start.test.ts:20:1)

```
2025-11-26 16:15:55 +01:00
Sebastian "Sebbie" Silbermann 49933c2eae [test] Move all files to .ts (1/6) (#85634) 2025-11-04 12:23:46 +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
Sebastian "Sebbie" Silbermann 6964259f6e [test] Rename "cache component" CI shards to "experimental" (#83101) 2025-08-28 11:44:00 +02:00
Wyatt Johnson badf4b6c17 feat(build): add client param parsing support for PPR routes (#82621)
### What?

This PR introduces comprehensive type-aware parameter tracking and
fallback handling for dynamic routes in PPR scenarios, with enhanced
client-side parameter resolution capabilities.

### Why?

When using client segment cache with dynamic routes, Next.js faced
several critical issues that prevented reliable client-side navigation:

**1. Parameter Resolution Inconsistencies**: The previous system had
inconsistent behavior when handling parallel route parameters, causing
unpredictable parameter resolution across different route segments. This
led to client-side navigation failures when encountering dynamic route
segments that weren't statically generated.

**2. Limited Parameter Type Awareness**: The routing system lacked
semantic understanding of different parameter types (dynamic, catchall,
optional catchall), making it impossible to implement advanced parameter
handling features or provide proper fallback behavior for different
parameter scenarios.

**3. Incomplete Fallback Parameter Collection**: The original
`getFallbackRouteParams()` used simple string-based tracking that
couldn't capture the full complexity of parameter relationships,
especially in parallel route scenarios where parameters might be defined
at different levels of the route tree.

**4. Client-Side Parameter Extraction Gaps**: The `getDynamicParam`
function had limitations in handling fallback route parameters and
lacked proper encoding/decoding mechanisms, leading to potential
client-side errors during route resolution.

**5. Configuration Validation Missing**: There was no validation to
ensure `clientParamParsing` was only enabled when `clientSegmentCache`
was also enabled, leading to potential misconfigurations in production.

These issues became critical blockers for implementing reliable
client-side parameter parsing in PPR scenarios, particularly for the
Vercel platform integration
(https://github.com/vercel/vercel/pull/13740).

### How?

- Introduces `DynamicParamTypes` and `OpaqueFallbackRouteParams` for
structured, type-aware parameter tracking
- Refactors `getFallbackRouteParams()` to use route modules for
comprehensive parameter collection across the routing tree
- Adds `resolveParallelRouteParams` function to eliminate parallel route
parameter inconsistencies
- Enhances `getDynamicParam` with proper fallback parameter handling,
encoding, and comprehensive catchall support
- Implements configuration validation in `assignDefaultsAndValidate()`
to prevent misconfigurations
- Adds clientParamParsing boolean to the routes manifest configuration
(needed for https://github.com/vercel/vercel/pull/13740)
- Updates build pipeline to properly handle enhanced fallback parameters
across static generation, export, and rendering phases

NAR-305

---------

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
2025-08-25 17:57:53 -06:00
Jiachi Liu b5b272062f [types] refactor shared types (#82844) 2025-08-20 23:41:52 +02:00
Jiachi Liu 7a59a7904a [test] fix cache components build error in next-form tests (#82841) 2025-08-20 19:21:01 +02:00
Jiachi Liu 50c172daa9 [test] update existing passed tests for cache components suite (#82830) 2025-08-20 19:14:25 +02:00
Hendrik Liebau 2036a5b1bf [Cache Components] Avoid cache misses when resuming a cached page (#82578)
When a page component (or a parallel route slot) is cached, but other
parts of the component tree are dynamic, we generate a partially static
shell at buildtime that's resumed at runtime. During the resume, we need
to ensure that the cache key is the same as during prerendering. This is
currently not the case because we automatically include the (unused)
`searchParams` prop in the cache key. Its value is a hanging promise
during prerendering, and a resolving promise at runtime, leading to a
cache miss when looking up the cached page data in the Resume Data Cache
(RDC). Subsequently, hydration errors might occur when the recomputed
result is different than the prerendered result.

Since search params are not allowed to be read in public cache scopes
anyways, we can pass erroring search params into the cached page,
instead of using a hanging promise, and omit them from the generated
cache key. We already used this technique when `cacheComponents` is not
enabled.

closes NAR-87
2025-08-12 21:40:33 +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
Hendrik Liebau 43b64ccdb5 Ignore pending revalidations during prerendering (#81621)
When reading a cache entry, we usually check its tags against the recently revalidated tags, and dismiss it, if it has any of those tags. However, this is only needed during dynamic requests, specifically during the rendering that follows a revalidating server action.

During the prerender validation in dev mode, we should not discard the cache entries based on the pending revalidation. The concurrently running dynamic rendering will handle discarding and recreating those cache entries. During build-time prerendering, there will never be any pending revalidated tags.

This fixes a bug where a different value was rendered when revalidating with a server action and then reloading the page afterwards (or triggering another unrelated revalidating server action).
2025-07-16 14:12:03 +02:00
Hendrik Liebau 4430409206 Discard prerendered route handler data from FS cache after revalidation (#81611)
After having revalidated a prerendered route handler, on the subsequent request we must discard the prerendered data from the file system cache, as we already do for pages and fetch caches as well.

> [!NOTE]  
> This PR is best reviewed with hidden whitespace changes.
2025-07-16 13:33:39 +02:00
Hendrik Liebau af74b4a36f Include use-cache test suite in the Cache Components tests (#81610)
We're splitting the test app routes between two root layouts, one for (partially) static pages that does not wrap its children in a Suspense boundary, and one for dynamic pages that adds a Suspense boundary above `body`, which opts those pages into fully dynamic rendering.

Two tests are expected to fail for now, because they revealed bugs related to revalidation, which will be fixed in follow-up PRs:
- https://github.com/vercel/next.js/pull/81611
- https://github.com/vercel/next.js/pull/81621

closes NAR-171
2025-07-16 13:05:25 +02:00
Hendrik Liebau d8fdb6ffa8 Simplify running test apps locally with ppr or dynamicIO enabled (#81668)
We want to respect the `__NEXT_EXPERIMENTAL_PPR` and `__NEXT_EXPERIMENTAL_CACHE_COMPONENTS` environment variables in the test apps, so that we can run them locally with these features enabled without needing to modify the config files.

So we're removing the requirement that `__NEXT_TEST_MODE` needs to be set at the same time. Usually you don't want to set this variable locally because it also changes other behavior in a few places.

This really has no downside, because it was already possible for users to set both variables and affect the flags, and now this can be done with a single variable. It allows us to keep the noise out of the test app's next config files.

We're also moving the assignments from the default config into `enforceExperimentalFeatures` to get the nice output when printing the experimental features in the CLI.
2025-07-16 12:13:54 +02:00
Wyatt Johnson f219487dcd feat(test): introduce cache components testing infrastructure (#81394)
### What?

Introduces a testing infrastructure to validate Next.js behavior with
the experimental Cache Components feature (`dynamicIO`) enabled. This PR
adds dedicated CI jobs and configuration to run a subset of existing
tests with Cache Components activated.

This has 271 more disabled test suites than the Legacy PPR test suite
manifest. The expectation is that we will be resolving the test failures
in followup PRs.

### Why?

Cache Components (dynamicIO) represents a significant architectural
change in how Next.js handles component caching and rendering. To ensure
a smooth transition when this becomes the default behavior, we need to:

1. **Validate compatibility** - Ensure existing applications continue to
work correctly when Cache Components is enabled
2. **Identify edge cases** - Catch potential issues early by running
tests in this new mode
3. **Build confidence** - Provide a safety net for the eventual
migration to Cache Components as the default

The manifest-based approach allows us to incrementally expand test
coverage as we fix compatibility issues, rather than attempting to run
all tests at once which would be overwhelming and block progress.

### How?

- **Test manifest** (`test/cache-components-tests-manifest.json`):
Defines which tests to run and tracks known failures that need
addressing
- **CI workflow changes**: Adds three new job groups that mirror
existing test jobs but with Cache Components enabled:
  - `test-cache-components-integration`
  - `test-cache-components-dev` (parallelized across 6 groups)
  - `test-cache-components-prod` (parallelized across 7 groups)
- **Conditional feature activation**: When
`__NEXT_EXPERIMENTAL_CACHE_COMPONENTS=true` is set during testing,
`dynamicIO` is automatically enabled unless explicitly disabled
- **Test adjustments**: Updates error message expectations in tests to
handle the different environment label ("Prerender" vs "Server") when
Cache Components is active

The infrastructure is designed to be temporary and will be removed once
Cache Components becomes the default behavior.

NAR-172
2025-07-10 11:48:57 -06:00