mirror of
https://github.com/vercel/next.js.git
synced 2026-09-20 02:25:18 +08:00
canary
711 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e9180eae2a |
errors: shorten "use cache" messages and unify them into one factory (#94300)
### What? Centralizes related <code>"use cache"</code> scope errors and rewrites them as shorter, actionable messages with consistent <code>Learn more:</code> links. It also updates the reachable revalidation errors for rendering and <code>generateStaticParams</code>. ### Why? The previous messages were long, inconsistent, and sometimes missing documentation links. Some new cache-specific revalidation messages were also hidden by an earlier render-phase error. The new messages name the constraint, give the immediate fix, and link to the relevant documentation. ### How? Adds centralized error factories and dedicated error pages for request data, cache configuration, private-cache composition, and revalidation. When an active App Router route is available, the messages include it. The error pages use consistent terminology and complete examples. The <code>unstable_cache()</code> reference now documents the request-dependent operations that these errors reject. ### Before and after Route-based examples use <code>/products</code>. Bracketed values are alternatives in matching order. For example, <code>[E1482, E1486, E1489]</code> maps to <code>[headers(), cookies(), request.url]</code>. Each runtime error contains one alternative, but the table groups messages with the same template. #### Messages that include the route | Cases | Before | After | | --- | --- | --- | | E1480 · <code>searchParams</code> in <code>"use cache"</code> | Route /products used <code>searchParams</code> inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await <code>searchParams</code> outside of the cached function and pass only the required search params as arguments to the cached function. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache | Route "/products": <code>searchParams</code> can't be read inside <code>"use cache"</code>. Await it outside the cached function and pass what you need as an argument.<br><br>Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache | | [E1482, E1486, E1489] · [<code>headers()</code>, <code>cookies()</code>, <code>request.url</code>] in <code>"use cache"</code> | Route /products used [<code>headers()</code>, <code>cookies()</code>, <code>request.url</code>] inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use [<code>headers()</code>, <code>cookies()</code>, <code>request.url</code>] outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache | Route "/products": [<code>headers()</code>, <code>cookies()</code>, <code>request.url</code>] can't be read inside <code>"use cache"</code>. Read it outside the cached function and pass what you need as an argument.<br><br>Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache | | [E1481, E1485, E1492] · [<code>cookies()</code>, <code>request.url</code>, <code>headers()</code>] in <code>unstable_cache()</code> | Route /products used [<code>cookies()</code>, <code>request.url</code>, <code>headers()</code>] inside a function cached with <code>unstable_cache()</code>. Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use [<code>cookies()</code>, <code>request.url</code>, <code>headers()</code>] outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/app/api-reference/functions/unstable_cache | Route "/products": [<code>cookies()</code>, <code>request.url</code>, <code>headers()</code>] can't be read inside <code>unstable_cache()</code>. Read it outside the cached function and pass what you need as an argument.<br><br>Learn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache | | [E1484, E1491] · <code>draftMode().enable()</code> in [<code>unstable_cache()</code>, <code>"use cache"</code>] | Route /products used "draftMode().enable()" inside [a function cached with <code>unstable_cache()</code>, "use cache"]. The enabled status of <code>draftMode()</code> can be read in caches but you must not enable or disable <code>draftMode()</code> inside a cache. See more info here: [https://nextjs.org/docs/app/api-reference/functions/unstable_cache, https://nextjs.org/docs/messages/next-request-in-use-cache] | Route "/products": <code>draftMode().enable()</code> can't be called inside [<code>unstable_cache()</code>, <code>"use cache"</code>]. Draft mode can be read inside a cached function, but enabling or disabling it must happen outside.<br><br>Learn more: [https://nextjs.org/docs/app/api-reference/functions/unstable_cache, https://nextjs.org/docs/messages/next-request-in-use-cache] | | [E1488, E1499] · <code>connection()</code> in [<code>unstable_cache()</code>, <code>"use cache"</code>] | Route /products used <code>connection()</code> inside [a function cached with <code>unstable_cache()</code>, "use cache"]. The <code>connection()</code> function is used to indicate the subsequent code must only run when there is an actual request, but caches must be able to be produced before a request, so this function is not allowed in this scope. See more info here: [https://nextjs.org/docs/app/api-reference/functions/unstable_cache, https://nextjs.org/docs/messages/next-request-in-use-cache] | Route "/products": <code>connection()</code> can't be called inside [<code>unstable_cache()</code>, <code>"use cache"</code>] because cached functions may run during prerendering, without an incoming request. Call it outside the cached function.<br><br>Learn more: [https://nextjs.org/docs/app/api-reference/functions/unstable_cache, https://nextjs.org/docs/messages/next-request-in-use-cache] | | E1494 · <code>connection()</code> in <code>"use cache: private"</code> | Route /products used <code>connection()</code> inside "use cache: private". The <code>connection()</code> function is used to indicate the subsequent code must only run when there is an actual navigation request, but caches must be able to be produced before a navigation request, so this function is not allowed in this scope. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache | Route "/products": <code>connection()</code> can't be called inside <code>"use cache: private"</code> because private cached functions may run during prefetching, without a navigation request. Call it outside the cached function.<br><br>Learn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private | | [E1483, E1495] · <code>revalidateTag("products")</code> in [<code>"use cache"</code>, <code>unstable_cache()</code>] | Route /products used "revalidateTag products" inside [a "use cache", a function cached with "unstable_cache(...)"] which is unsupported. To ensure revalidation is performed consistently it must always happen outside of renders and cached functions. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering | Route "/products": <code>revalidateTag("products")</code> can't be called during render, inside a cached function, or inside <code>generateStaticParams</code>. Call it from a Server Action or Route Handler instead.<br><br>Learn more: https://nextjs.org/docs/messages/revalidate-in-use-cache | | During render | Route /products used "revalidateTag products" during render which is unsupported. To ensure revalidation is performed consistently it must always happen outside of renders and cached functions. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering | Route "/products": <code>revalidateTag("products")</code> can't be called during render, inside a cached function, or inside <code>generateStaticParams</code>. Call it from a Server Action or Route Handler instead.<br><br>Learn more: https://nextjs.org/docs/messages/revalidate-in-use-cache | | Inside <code>generateStaticParams</code> | Route /products used "revalidateTag products" inside <code>generateStaticParams</code> which is unsupported. To ensure revalidation is performed consistently it must always happen outside of renders and cached functions. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering | Route "/products": <code>revalidateTag("products")</code> can't be called inside <code>generateStaticParams</code>. Call it from a Server Action or Route Handler instead.<br><br>Learn more: https://nextjs.org/docs/messages/revalidate-in-use-cache | #### Other messages | Cases | Before | After | | --- | --- | --- | | [E1477, E1490] · Nested cache with [short <code>expire</code>, <code>revalidate: 0</code>] | A "use cache" with [short <code>expire</code> (under 5 minutes), zero <code>revalidate</code>] is nested inside another "use cache" that has no explicit <code>cacheLife</code>, which is not allowed during prerendering. Add <code>cacheLife()</code> to the outer "use cache" to choose whether it should be prerendered [with longer <code>expire</code>, with non-zero <code>revalidate</code>] or remain dynamic [with short <code>expire</code>, with zero <code>revalidate</code>]. Read more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife | Route <code>"/products"</code>: A nested <code>"use cache"</code> with [a short <code>expire</code> (under 5 minutes), <code>revalidate: 0</code>] is inside an outer <code>"use cache"</code> that has no <code>cacheLife()</code>. Add <code>cacheLife()</code> to the outer one to choose whether to prerender it [with a longer <code>expire</code>, with a non-zero <code>revalidate</code>] or keep it dynamic [with a short <code>expire</code>, with <code>revalidate: 0</code>].<br><br>Learn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife | | E1478 · External promise | Filling a "use cache" entry appears to be stuck on shared state from the outer render scope. The same function completed when run in isolation, which usually means a module-scoped value (for example a top-level Map used to dedupe fetches) is joining a promise created outside the cache. "use cache" already dedupes calls with the same arguments within a request and across requests on the same server instance, so the surrounding dedupe layer is both unnecessary and the likely cause. Remove it and rely on "use cache" alone for deduping.<br><br><em>No documentation link.</em> | Route <code>"/products"</code>: A <code>"use cache"</code> function is awaiting a promise created outside it. The same call completed when run in isolation, so a module-scoped value (often a top-level <code>Map</code> used to dedupe fetches) is most likely blocking it. <code>"use cache"</code> already dedupes calls with the same arguments. Remove the surrounding dedupe layer.<br><br>Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache | | [E1479, E1498] · [<code>cacheTag()</code>, <code>cacheLife()</code>] outside a cached function | [<code>cacheTag()</code>, <code>cacheLife()</code>] can only be called inside a "use cache" function.<br><br><em>No documentation link.</em> | Route <code>"/products"</code>: [<code>cacheTag()</code>, <code>cacheLife()</code>] can only be called inside a <code>"use cache"</code> or <code>"use cache: private"</code> function.<br><br>Learn more: [https://nextjs.org/docs/messages/cache-tag-outside-use-cache, https://nextjs.org/docs/messages/cache-life-outside-use-cache]<br><br>Outside an App Router route, the same message is shown without the route prefix. | | E1487 · Prerender timeout | Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or dynamic data were used inside "use cache".<br><br><em>No documentation link.</em> | Route <code>"/products"</code>: A <code>"use cache"</code> function took too long during prerendering. The most common cause is passing unresolved request-specific arguments, such as <code>params</code> or <code>searchParams</code>, into the cached function. Resolve the data before calling the function and pass only the values you need.<br><br>Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache | | E1493 · Private cache inside a public cache | "use cache: private" must not be used within "use cache". It can only be nested inside of another "use cache: private".<br><br><em>No documentation link.</em> | Route <code>"/products"</code>: <code>"use cache: private"</code> can't be nested inside <code>"use cache"</code> because a shared cached function can't depend on private request data. Nest it only inside another <code>"use cache: private"</code>.<br><br>Learn more: https://nextjs.org/docs/messages/use-cache-private-composition | | E1496 · Private cache without a request | "use cache: private" cannot be used outside of a request context.<br><br><em>No documentation link.</em> | Route <code>"/products"</code>: <code>"use cache: private"</code> needs an active request, so it can't be used during <code>generateStaticParams</code> or other build-time contexts. Move it to a request-time component or function.<br><br>Learn more: https://nextjs.org/docs/messages/use-cache-private-composition | | E1497 · Private cache inside <code>unstable_cache()</code> | "use cache: private" must not be used within <code>unstable_cache()</code>.<br><br><em>No documentation link.</em> | Route <code>"/products"</code>: <code>"use cache: private"</code> can't be used inside <code>unstable_cache()</code> because <code>unstable_cache()</code> uses a shared cache that can't contain private request data. Call the private cached function outside <code>unstable_cache()</code>.<br><br>Learn more: https://nextjs.org/docs/messages/use-cache-private-composition | ### Runtime verification - Exercised the 13 route-based message IDs through minimal dev-runtime reproductions. Twelve reached the new factories from userland, with byte-identical output across three requests each. - The `request.url` error for `"use cache"` Route Handlers is currently limited to the prerender path. A dynamic request captured by a cached closure can bypass that tracking; this is existing framework behavior to follow up separately. - Passing the `searchParams` promise into a nested cached function can still surface the earlier synchronous dynamic-API error before this factory. The new message is verified when the cache scope reads its own `searchParams` value. - A follow-up preview verification triggered 17 of the 19 rewritten messages from userland with byte-identical output. The timeout-driven external-promise and prerender-timeout messages were verified in source and through their focused test coverage. ### Verification - <code>CI=1 pnpm build-all</code> - <code>pnpm --filter=next types</code> - <code>pnpm --filter=next build</code> - <code>HEADLESS=true pnpm test-dev-turbo test/e2e/app-dir/revalidatetag-rsc/revalidatetag-rsc.test.ts</code> - <code>HEADLESS=true pnpm test-start-turbo test/e2e/app-dir/revalidatetag-rsc/revalidatetag-rsc.test.ts</code> - <code>NEXT_SKIP_ISOLATE=1 HEADLESS=true pnpm test-dev-webpack test/e2e/app-dir/cache-components-errors/use-cache.test.ts -t 'cacheLife with (expire < 5 minutes|revalidate: 0)'</code> (6 tests and 6 snapshots passed) - <code>pnpm test-dev test/e2e/app-dir/cache-components-errors/use-cache.test.ts --projects jest.config.*</code> (42 tests and 42 snapshots passed across Turbopack and webpack) - <code>pnpm test-dev test/e2e/app-dir/use-cache-hanging/use-cache-hanging.test.ts --projects jest.config.*</code> (10 tests and 8 snapshots passed across Turbopack and webpack) - <code>pnpm test-dev test/e2e/app-dir/use-cache-configured-timeout/use-cache-configured-timeout.test.ts --projects jest.config.*</code> (4 tests and 2 snapshots passed across Turbopack and webpack) - Prettier, ESLint, and Alex on the changed source, tests, and error pages <!-- NEXT_JS_LLM --> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
89d017eac4 |
Pages Router: Deprecate React 18 support (#97689)
## Summary - warn during `next dev` and `next build` when React 18 is installed, while keeping `next start` quiet - explain that React 18 remains supported in Next.js 16 but will be removed in Next.js 17 - update the React version guidance with React 19 and TypeScript type upgrade commands ## Verification - `NEXT_TEST_PREFER_OFFLINE=1 pnpm test-dev-turbo test/e2e/react-current-version/react-current-version.test.ts` - `NEXT_TEST_REACT_VERSION=18.3.1 NEXT_TEST_PREFER_OFFLINE=1 pnpm test-dev-turbo test/e2e/react-current-version/react-current-version.test.ts` - targeted production build/start coverage passed with React 18 and React 19 - Not passing: `pnpm --filter=next types` (existing unrelated errors in `httpget.ts`, `image-optimizer.ts`, `proxy-request.ts`, telemetry typings, and compiled declarations) - Not passing: `pnpm lint` (existing unused Turbo Tasks check) <!-- NEXT_JS_LLM --> |
||
|
|
18766e9071 |
docs: clarify beforeInteractive placement for root layouts (#97643)
Fixes: https://github.com/vercel/next.js/issues/97602 |
||
|
|
7cb68c1282 |
docs: create client-side fetching guide (#96341)
## What changed - Expands the SPA data-fetching guidance with focused SWR and TanStack Query guides. - Covers client-only fetching, optional Server Component seeding, shared cache identities, and optimistic mutations. - Explains how the Next.js server and client caches relate to library-owned browser caches, including SWR `preload` and TanStack Query hydration with Cache Components. - Aligns the examples with `next-spa-patterns` and the team chat demo. ## Validation - Prettier and diff checks pass for the updated guides. - `next-spa-patterns` passes TypeScript checks. |
||
|
|
ec1a44d0f1 |
docs: runtime prefetching -> optimizing prefetching (#96934)
With the latest GA changes, when using Cache Components with Partial
Prefetching:
> prefetch={true} turns on prefetching
These changes try to align around that idea.
- runtime prefetching guide is now about optimizing
- various changes in prose across docs
- even fix an error page for pages router, which had a broad title
---------
Co-authored-by: Aurora Scharff <aurora.sofie@gmail.com>
|
||
|
|
44c3ec6bb5 |
docs: use relative doc links in instant-navigation error pages (#96672)
These links no longer need to point to preview. |
||
|
|
3de2d1a213 |
Unify allow-runtime with Partial Prefetching (#96106)
Removes the "allow-runtime" prefetch config, and turns its behavior on implicitly wherever Partial Prefetching is enabled. The original motivation for "allow-runtime" was to give apps more control over server costs triggered by prefetches. Until a route explicitly opts in, prefetches would only be served from the CDN, not from the server. The problem, though, was it was very confusing to know when to add or remove this configuration. The incentive for many apps was to add it everywhere, with no clear signal for when to remove it. Our updated thinking is that Partial Prefetching itself already provides sufficient protection against runaway prefetching costs: per-link prefetches only happen on Link components that explicitly opt in with the prefetch prop. The optimizations landed earlier in this stack also make allow-runtime less necessary: on pages where all the content is statically renderable, prefetches are served from the static cache and no runtime request is ever issued; only a page that accesses non-static data is prefetched at runtime. The upshot of this decision is that runtime versus static becomes an internal optimization; the same content gets prefetched regardless of whether or how Next.js is able to optimize it. |
||
|
|
f2e6abb47e |
Throw for empty or incomplete generateStaticParams results with output: export (#95969)
> [!TIP] > This PR is best reviewed commit by commit. ### Why? With `output: 'export'`, an empty array or incomplete params can be reported as a missing `generateStaticParams` function, even when the function exists. ### How? - Throw when any `generateStaticParams` invocation returns `[]`. - Throw when any composed parent and child params object omits a dynamic route parameter. - Extend the troubleshooting page added in #95968 with the export-specific cases. Stacked on #95968. Supersedes #95388. <!-- NEXT_JS_LLM --> Co-authored-by: SukkaW <isukkaw@gmail.com> |
||
|
|
81643544fc |
Throw when generateStaticParams returns invalid values (#95968)
> [!TIP]
> This PR is best reviewed commit by commit.
### Why?
`generateStaticParams` must return an array of objects, but Next.js does
not currently provide a clear error when it returns something else.
### How?
- Throw when `generateStaticParams` does not return an array.
- Throw when an item in the returned array is not an object.
- Keep allowing `{}`. The follow-up rejects it with `output: 'export'`
when it leaves a dynamic route parameter missing.
Follow-up: #95969
Supersedes #95388.
<!-- NEXT_JS_LLM -->
Co-authored-by: SukkaW <isukkaw@gmail.com>
---------
Co-authored-by: Joseph <joseph.chamochumbi@vercel.com>
|
||
|
|
025e8535dd |
Validate server reference IDs during manifest lookup (#96007)
https://github.com/vercel/next.js/security/advisories/GHSA-955p-x3mx-jcvp Co-authored-by: Josh Story <story@hey.com> |
||
|
|
420ab0c7e1 |
docs: add route-side URL data audit to the Partial Prefetching adoption guide (#95389)
## What Follow-up to #95365. Documents adopting Partial Prefetching end to end: - Restructures the [Adopting Partial Prefetching guide](https://github.com/vercel/next.js/blob/canary/docs/01-app/02-guides/adopting-partial-prefetching.mdx) around the two paths: enable `partialPrefetching` and audit every `<Link prefetch={true}>` against a per-case decision table, or adopt incrementally per route with the [`instant-link-prefetch-partial`](https://nextjs.org/docs/messages/instant-link-prefetch-partial) insight as the worklist. Adds `Auditing routes for URL data` and `Prefetching URL data` sections. - Adds the `remove-partial-prefetch` codemod, which strips the redundant per-route `prefetch = 'partial'` exports once the flag is on while preserving comments and other `prefetch` values. - Adds the `next-partial-prefetching-adoption` skill that sequences the guide for agents: audit, enable + codemod, URL-data sweep, verify, optional runtime prefetching. - Aligns the `instant-link-prefetch-partial` error page, `<Link>` reference, glossary, and Interactive apps guide with the same prefetch model. ## Why With the flag on, `<Link prefetch={true}>` no longer delivers dynamic content, and shell validation flags `params`/`searchParams` reads outside `<Suspense>`. Adopters need one guide that sequences the audit, the flag, and both insights, and an agent skill that follows it. Stacked on #95365 (base: `codex/instant-shell-link-data`) since it links to the `instant-shell-url-data` error page that PR introduces. GitHub will retarget to `canary` when that merges. <!-- NEXT_JS_LLM_PR --> |
||
|
|
303f7ffd4a |
docs: revalidateTag with expire zero, for route handlers (#95760)
The error page did not mention an alternative for Route Handlers. |
||
|
|
76628b4f9b |
[PP] Surface URL data during prefetching as an Instant insight with rule page (#95365)
## What? Adds the Instant Insight + rule page for the Partial Prefetching shell validation (Janka's #95151): with `partialPrefetching` on, a route that reads `params`/`searchParams` outside `<Suspense>` blocks the extraction of the per-route **App Shell** that every link to the route shares. Surfaced as an Instant insight (not a redbox), with two fix cards: Stream (wrap in `<Suspense>`) · Allow blocking route (`instant = false`). The insight fires both at link-prefetch time and during a client-side navigation, so it covers a `<Link prefetch>` into the route as well as a plain client navigation to it. Demos: - [99-link-params-gsp](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/99-link-params-gsp) — `<Link prefetch>` to a `generateStaticParams` route that awaits `params` unguarded. - [117-subnav-params](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/117-subnav-params) — client-side navigation into a `[slug]` route that reads `params` outside `<Suspense>`. - [118-subnav-search-params](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/118-subnav-search-params) — client-side navigation into a route that reads `searchParams` outside `<Suspense>`. Follow-up: #95389 documents the route-side audit in the Adopting Partial Prefetching guide (draft, to be coordinated). ## How? - Family-wide polish across all 16 insight pages while aligning the new one: consistent "Verifying the fix" wording, normalized `Learn more:` link texts (target title for guides, bare code name for API references), "App Shell" used consistently, CLS guidance reframed as "minimizing layout shift", prose cleanups (no semicolons, no code-initial sentences), and the insight-error-page skill updated to match. - New `errors/instant-shell-url-data.mdx` rule page, structured like the rest of the insight family (`blocking-prerender-client-hook`, `instant-link-prefetch-partial`); added to every page's Related Insights. New **URL data** glossary entry ("varies per link, not per session"), linked from the page. - `createLinkBodyErrorInNavigation` re-pointed to the page and classified as a navigation-time insight (`inNavigation` → Instant tab) using the shared `linkCards` fix cards. - Common insight format for the message: headline "Next.js encountered URL data outside of Suspense", consequence "may prevent the navigation from being instant, leading to a slower user experience" ("may", since boundaries or a runtime prefetch can still keep the navigation instant), and the two fixes phrased as `[stream] Provide a placeholder with <Suspense fallback={...}> around the data access` and `[block] Set export const instant = false to allow a blocking route`. The shell mechanics are explained on the docs page rather than in the headline. - Second fix reframed from "Disable validation" (group `ignore`) to **Allow blocking route** (group `block`), matching the `blocking-prerender-*` family: `instant = false` marks the segment as allowed to block rather than opting the route out of validation. - Metadata/viewport variants: only the headline term is aligned ("link data" → "URL data") plus a small grammar fix; framing, fix cards, and docs URLs stay on the existing `-metadata-runtime`/`-viewport-runtime` pages unchanged. - `errors.json` regenerated append-only (codes 1407-1409), and the docs opt-out wording updated to the new silence-free phrasing. - e2e snapshots updated for all four configs (dev/start × default/partial-prefetching); unit tests for the matcher, cards, classification, and `isInstantNavigationError`. <!-- NEXT_JS_LLM_PR --> |
||
|
|
6c5f3d5775 |
Rename Copy as prompt to Copy prompt, convert FixOption to FixCard (#95309)
## Why Standardize the Insight fix UI across the dev overlay and docs, and round out the docs side with a proper family index at the bottom of every page. ## What - Dev overlay: **Copy as prompt** -> **Copy prompt**; bumped the pill padding to match the new docs button. - Error pages (`errors/*.mdx`, 15 files): `<FixOption>` -> `<FixCardGrid>`/`<FixCard>` with snippets copied verbatim from `instant-guidance-data.ts`; all `https://preview.nextjs.org/docs/...` URLs converted to relative `/docs/...`. - Every Insight error page now ends with a `## Related Insights` index listing the other 14 Insight pages (self omitted). - `instant-navigation.mdx` and `migrating-to-cache-components.mdx`: dropped the stray trailing `}` snippet line so guide cards match dev-overlay heights; added a one-line Copy prompt note linking to `#ai-workflow`. - `insight-error-page` skill: replaced the "Useful links" guidance with "Related Insights" (full family index, no API refs/guides) and matching audit-checklist line. - Minor cleanup in `instant-guidance-data.ts` (trimmed verbose JSDoc to non-obvious bits). ## How Paired with vercel/front#75443 which adds the Copy prompt button to `<FixCard>` and deletes the legacy `<FixOption>`. `pnpm --filter=next types` clean, 23 `instant-guidance-data` tests pass. <!-- NEXT_JS_LLM_PR --> |
||
|
|
e37c6d636c |
Enhance ESLint rule no-location-assign-relative-destination (#93057)
- Implements `location` scope check (suggested by @bgw in https://github.com/vercel/next.js/pull/92900#discussion_r3107167621), ensuring `location` is a true global variable before reporting. - Implements basic variable tracking (suggested by @icyJoseph in https://github.com/vercel/next.js/pull/93057#issuecomment-4281583840) --------- Co-authored-by: Benjamin Woodruff <benjamin.woodruff@vercel.com> |
||
|
|
6c22d02ce0 |
docs(errors): reorder blocking-prerender-dynamic fixes to Stream, Cache, Block (#95198)
The runtime error message for `blocking-prerender-dynamic` lists fixes in the order **[stream] → [cache] → [block]** (see `packages/next/src/server/app-render/blocking-route-messages.ts`). Every other surface (dev overlay fix cards, the blog post on `nextjs.org/blog/next-16-3-instant-navigations`, the in-post bullets, the `## Stream, Cache, or Block` section heading) uses the same order. Only this docs page was out of sync, listing Cache first. This PR: - Swaps the order of the `FixOption` cards under `## Ways to fix this` to `stream → cache → block`. - Swaps the body sections `## Cache the component or data` and `## Wrap in or move into Suspense` to match. No content changes inside either section — pure reorder. |
||
|
|
5ad38b43bc |
docs(insights): restructure error pages and link to preview docs (#95193)
### What? Restructure the 15 Insight error pages (`errors/blocking-prerender-*.mdx`, `errors/instant-*.mdx`) so they orient the reader before diving into fixes, and point at the preview docs for the new 16.3 Instant Navigations guide and APIs. ### Why? These pages are the first thing devs see when they click the doc link from the dev overlay or the build output for a blocking-route / instant-navigation error. Previously they opened straight into the technical explanation with no signal that this error is part of the new 16.3 Instant Navigations feature, and several callouts mixed unrelated concerns (debug flags inside a top-of-page "Good to know", duplicated "Useful links" footers). ### How? - **Intro callout box** added to every page, pointing at the 16.3 launch blog post and the migration guide so newcomers have an anchor before reading the fix. - **`## Verifying the fix` section** added near the bottom, gathering the debug tips (empty-shell warning, `--debug-prerender`, `--debug-build-paths`) that previously sat in a top-of-page "Good to know" callout where they were misplaced. - **Removed** duplicated "Useful links" footers (already cross-linked in body), removed the misplaced top-of-page debug callout. - **Switched all 473 doc links** to `https://preview.nextjs.org/docs/...` so they resolve against the unpublished 16.3 docs (the live nextjs.org docs don't have the Instant Navigations guide or the route-segment-config/instant API reference yet). Split out of #95186 (Copy-as-prompt checklist) which was the same branch but a separate feature. Closes NEXT- <!-- NEXT_JS_LLM_PR --> |
||
|
|
b0dde9cf27 |
docs: expand io reference (#95147)
Rewrites the `io()` API reference around what it expresses: with Cache Components `await io()` keeps the operation that follow afterward out of the static shell. Adds Server/Client usage examples and a composition note, a "When you don't need `io()`" section, and reframes the `connection()` comparison around prefetching. --------- Co-authored-by: Aurora Scharff <66901228+aurorascharff@users.noreply.github.com> Co-authored-by: Aurora Scharff <aurora.sofie@gmail.com> |
||
|
|
d4b234030d |
docs: clarify /_not-found failures and <html> attribute reads under Cache Components (#95163)
## Summary When the root layout reads request data (`cookies()`, `headers()`) under Cache Components, the validation error often surfaces on `/_not-found` — a real prerendered route that inherits the root layout, even though the user has no `not-found.tsx` file. This is consistently confusing (#67532), so: - `errors/blocking-prerender-runtime.mdx` and `errors/blocking-prerender-dynamic.mdx`: added a gotcha bullet pointing the fix at the root layout when the failing route is `/_not-found`. - `docs/01-app/02-guides/migrating-to-cache-components.mdx`: added a `Good to know` callout in the `cookies, headers, and searchParams` section linking to the existing [Themes recipe](/docs/app/guides/preventing-flash-before-hydration#themes) for the `<html data-theme>` case, since attributes on the root element can not be wrapped in `<Suspense>`. ## Verification - `npx alex` clean on all three files. <!-- NEXT_JS_LLM_PR --> --------- Co-authored-by: Joseph Chamochumbi <joseph.chamochumbi@vercel.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
5ed0a5c988 |
dev-overlay: wire Link prefetch={true} Partial Prefetching warning into Insights (#94798)
### What?
Wires the dev-only `<Link prefetch={true}>` Partial Prefetching warning
from [#94672](https://github.com/vercel/next.js/pull/94672) into the
Instant Insights surface. Code frame, call stack, three fix cards:
**Upgrade** `prefetch = 'partial'` · **Disable** the prop · **Ignore**
with `instant = false`.
Demo:
[93-link-prefetch-without-partial](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/93-link-prefetch-without-partial).
### How?
- Warning factored into a shared `instant-messages.ts` factory.
- New `link-prefetch-partial` overlay kind + `Instant` label +
`InstantRuntimeError` dispatcher.
- Two new fix-card groups: **Upgrade** (amber, arrow-up), **Disable**
(gray, minus).
- New `instant-link-prefetch-partial.mdx` rule page + "Auditing existing
calls" section in the adoption guide.
- Unit tests for the matcher, cards, and `isInstantNavigationError`.
### Related
- [#94818](https://github.com/vercel/next.js/pull/94818) — broader
Partial Prefetching docs cleanup. Lands independently.
- [vercel/front#73592](https://github.com/vercel/front/pull/73592) —
next-site `upgrade` + `disable` `FixGroup` values.
|
||
|
|
ab4b1918c7 |
docs(cache-components): clarify allow-runtime, sync-IO and instant=false, CLS fallback (#94997)
### What? Docs-only follow-ups for Cache Components and Partial Prefetching, from agent migration friction logs and Joseph's review of [#95082](https://github.com/vercel/next.js/pull/95082). - **`adopting-partial-prefetching.mdx`** — reframe the `allow-runtime` row in the audit table (it's an enhancement, not the `<Link prefetch={true}>` warning fix; the per-route opt-in is `prefetch = 'partial'`). - **`migrating-to-cache-components.mdx`** — split the `## Enable Cache Components` section into before-flag (remove `dynamic` / `revalidate` / `fetchCache`) and after-flag (translate `revalidate`, `fetchCache`, `unstable_cache`, `fetch` cache options) steps. Flag the `revalidateTag` second-argument requirement, with a Before / After example. Add two Good-to-know callouts: off-grid `revalidate` values map to the closest `cacheLife` profile; `instant = false` is allowed-to-block, not forced-dynamic. - **`blocking-prerender-current-time` / `-random` / `-crypto`** (and their `-client` siblings) — drop the misleading "Don't want this validation?" opt-out section. `instant = false` is an instant-navigation knob and doesn't suppress sync-IO prerender errors. - **Remaining `blocking-prerender-*` pages** — standardize the CLS fallback callout so they all link the canonical section. ### Why? Friction logs surfaced four recurring misreads: 1. Devs expected `prefetch = 'allow-runtime'` to silence the `<Link prefetch={true}>` warning. The docs implied it would. 2. The migration guide mixed `dynamic` removal with `unstable_cache` translation, so it wasn't clear which had to happen before the flag and which after. 3. `revalidateTag` now requires a cache profile, but the on-demand revalidation section didn't say so. 4. Sync-IO error pages still carried a "Don't want this validation?" opt-out that doesn't actually work for those errors. |
||
|
|
f965c00411 |
Insights: drop irrelevant fix cards from instant errors (#94926)
### Why? Two Insight fix cards were misleading: 1. **`generateStaticParams` showed up on every runtime/client-hook insight.** One error covers `cookies()` / `headers()` / `params` / `searchParams`. GSP only applies to `params`; for the others it's noise. Even for `params` it nudges devs to make the route static instead of fixing the immediate error. 2. **`"use cache"` showed up on `connection()` triggers.** Caching `connection()` is contradictory. Both manifest on initial load and in-navigation (the fix-card sets are shared). ### What? 1. **Drop the GSP card** from runtime + client-hook sets. Affects [01-cookies-body](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/01-cookies-body), [03-params-body](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/03-params-body), [90-client-use-params](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/90-client-use-params), [41-subnav-cookies](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/41-subnav-cookies), [42-subnav-fetch](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/42-subnav-fetch). 2. **Filter `"use cache"`** when the cause is `connection()`. Affects [05-connection-body](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/05-connection-body), [08-connection-body-dynamic](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/08-connection-body-dynamic), [31-connection-in-metadata](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/31-connection-in-metadata), [33-connection-in-viewport](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/33-connection-in-viewport). [06-uncached-fetch-body](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/06-uncached-fetch-body) keeps the Cache card. ### How? - `getCards()` filters the cache card when `cause === 'connection'`. - New `deriveCauseFromCodeFrame()` helper detects `connection(` on the highlighted code-frame line. - `ParamClientHookDynamicError` collapsed into `ClientHookDynamicError`. - CLI/build messages: dropped the GSP bullet; added `(does not apply to \`connection()\`)` on the cache bullet. - Docs: removed `For known params, prerender` sections; added a connection caveat on dynamic/metadata-dynamic/viewport-dynamic pages. <!-- NEXT_JS_LLM_PR --> |
||
|
|
64429129c0 |
docs: fix typo in slot-missing-default.mdx (#94531)
Fixed a typo in `errors/slot-missing-default.mdx`: - `Optiona` → `Optional` <!-- Thanks for opening a PR! Your contribution is much appreciated. To make sure your PR is handled as smoothly as possible we request that you follow the checklist sections below. Choose the right checklist for the change(s) that you're making: ## For Contributors ### Improving Documentation - Run `pnpm prettier-fix` to fix formatting issues before opening the PR. - Read the Docs Contribution Guide to ensure your contribution follows the docs guidelines: https://nextjs.org/docs/community/contribution-guide ### Fixing a bug - Related issues linked using `fixes #number` - Tests added. See: https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ### Adding a feature - Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. (A discussion must be opened, see https://github.com/vercel/next.js/discussions/new?category=ideas) - Related issues/discussions are linked using `fixes #number` - e2e tests added (https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs) - Documentation added - Telemetry added. In case of a feature if it's used or not. - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ### Signed commits - This repository requires verified commit signatures on protected branches. - If this pull request is blocked for unsigned commits, re-sign the commits and force-push the branch. - A `Signed-off-by` line in the commit message is not enough. ## For Maintainers - Minimal description (aim for explaining to someone not on the team to understand the PR) - When linking to a Slack thread, you might want to share details of the conclusion - Link both the Linear (Fixes NEXT-xxx) and the GitHub issues - Add review comments if necessary to explain to the reviewer the logic behind a change ### What? ### Why? ### How? Closes NEXT- Fixes # --> |
||
|
|
0a518a84e9 |
instant: build fix-card Copy AI prompt dynamically from title + link (#94637)
### What
The dev-overlay fix cards' `Copy AI prompt` button used to copy a
multi-paragraph instruction string baked into each card (71 prompts
across docs + runtime). This PR replaces that with a dynamic template
the button builds at click time:
```
Apply the [Stream] "Wrap in or move into Suspense" fix to the Next.js Insight raised in this project.
Steps:
1. The failing code is in the error block below — it may be a data-access call, a hook call, a metadata or viewport export, or a component. The fix applies to that exact code; don't touch unrelated files.
2. Read the rule docs at <rule-url> for the full Insight explanation, then read the fix section at <fix-url>. Pick the pattern under "### Patterns" that matches the failing code, then read "### Gotchas" before editing — they list constraints that are easy to miss. Use the canonical imports and code shape from the page; don't improvise variations.
3. Apply the chosen pattern to the code identified in step 1.
## Error Type
Blocking Route
## Error Message
Route "/01-cookies-body": ...
at Page (app/01-cookies-body/page.tsx:4:26)
## Code Frame
> 4 | const c = await cookies();
| ^
...
Next.js version: 16.3.0-canary.47 (Turbopack)
```
### Why
Old verbatim prompts repeated what the docs already say and never
anchored the fix to the actual error. The new template:
- Names the chosen fix (group badge + title) so the agent picks the
right pattern.
- Points at the rule docs AND the specific fix anchor, with explicit
instructions to read `### Patterns` and `### Gotchas`.
- Prepends the live error block (same shape the existing 'Copy error
info' button emits) so the agent has the failing file, line, code frame,
and stack inline — no need to re-fetch the dev overlay.
### Changes
- `FixCard` type: `prompt?: string` → `copyable?: boolean`
- `CopyPromptButton`: takes `title + group + link + generateErrorInfo`,
builds the prompt
- Refactored `generateErrorInfo` from `errors.tsx` into a shared
`utils/generate-error-info.ts` so the existing 'Copy error info' button
and the fix-card 'Copy AI prompt' button format the error block
identically
- 14 error MDX pages: every `prompt={...}` removed (36 strings)
- `instant-guidance-data.ts`: every `prompt: '...'` → `copyable: true`
(35 strings)
- Skill (`.agents/skills/insight-error-page/SKILL.md`): updated
### Pairs with
vercel/front#73087 — same template in the docs-site `<FixOption>`
(without the error block, since there's no live error on a docs page).
<!-- NEXT_JS_LLM_PR -->
|
||
|
|
0553b34542 |
doc: instant navs runtime story (#93204)
- changes getting started -> caching - new guide for instant navs - new guide for runtime-prefetching (most pending stuff is here) - x-refs between docs - App Shell mentions in other docs (ISR w/ CC) --------- Co-authored-by: Aurora Scharff <66901228+aurorascharff@users.noreply.github.com> Co-authored-by: Aurora Scharff <aurora.sofie@gmail.com> |
||
|
|
23b1977efc |
docs: remove unstable_disableValidation recommendations (#94608)
### What?
Removes `unstable_disableValidation` recommendations from all 14
insight-kind error pages and the `generateViewport` API reference. The
key on `unstable_instant`'s object form is not going to ship as a
recommended public API.
### Why?
Each error page's **"Don't want this validation?"** block previously
listed three opt-out levels:
1. **One segment** — `export const unstable_instant = false`
2. ~~**Layout and its children** — `export const unstable_instant = {
unstable_disableValidation: true }`~~ ← dropped
3. **Entire app** — `experimental.instantInsights.validationLevel:
'manual-warning'`
Dropping the middle bullet aligns the docs with the public-API surface
we intend to keep.
### How?
- Removed the `Layout and its children` bullet across 14 `errors/*.mdx`
pages.
- Removed the now-broken `See [Don't want this validation?] for the
subtree-wide opt-out` reference in the in-body **Gotchas** sections.
- Updated the `generate-viewport.mdx` API reference to drop the same
dangling reference.
- Framework source (`unstable_disableValidation` parsing in
`app-segment-config.ts` and runtime handling in `instant-config.tsx`) is
unchanged — that's a separate framework concern.
<!-- NEXT_JS_LLM_PR -->
|
||
|
|
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. |
||
|
|
5b99d26df8 |
instant: polish client-hook overlay wording, cards, and docs links (#94496)
### What? Polishes the dev-overlay UX for the client-hook prerender error after Josh's framework fix landed in [#94494](https://github.com/vercel/next.js/pull/94494). The overlay now names the hook in the headline and shows per-hook fix cards. ### Why? Different hooks need different fixes. `useSearchParams` always suspends, but `generateStaticParams` doesn't apply to it. `useParams` is the only hook GSP resolves at build time. `usePathname` and `useSelectedLayoutSegment(s)` need a Suspense boundary or the `[block]` export. ### How? - Headline now reads "Next.js encountered URL data `useX()` in a Client Component outside of `<Suspense>`", matching the body factory wording. - Per-hook card sets in `instant-guidance-data.ts`: `useSearchParams` → Stream + Block; `useParams` → Stream + GSP + Block; `usePathname` / `useSelectedLayoutSegment(s)` → Stream + Block. - Build-time message in `ClientHookDynamicError` / `ParamClientHookDynamicError` matches the overlay card set. - Companion docs page: [vercel/front#72622](https://github.com/vercel/front/pull/72622). ### Verification Demo scenarios on the [error-messages-overhaul test app](https://error-messages-overhaul-ibsl.labs.vercel.dev/): [88-client-use-pathname](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/88-client-use-pathname), [89-client-use-search-params](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/89-client-use-search-params), [90-client-use-params](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/90-client-use-params), [91-client-use-selected-layout-segment](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/91-client-use-selected-layout-segment), [92-client-use-selected-layout-segments](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/92-client-use-selected-layout-segments). <!-- NEXT_JS_LLM_PR --> --------- Co-authored-by: Josh Story <gnoff@storyposted.com> |
||
|
|
1e601b6b8b |
docs: add pnpm installation step to module-not-found error page (#93773)
Added missing pnpm command for installing dependencies to ensure consistency with other documentation pages. <!-- Thanks for opening a PR! Your contribution is much appreciated. To make sure your PR is handled as smoothly as possible we request that you follow the checklist sections below. Choose the right checklist for the change(s) that you're making: ## For Contributors ### Improving Documentation - Run `pnpm prettier-fix` to fix formatting issues before opening the PR. - Read the Docs Contribution Guide to ensure your contribution follows the docs guidelines: https://nextjs.org/docs/community/contribution-guide ### Fixing a bug - Related issues linked using `fixes #number` - Tests added. See: https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ### Adding a feature - Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. (A discussion must be opened, see https://github.com/vercel/next.js/discussions/new?category=ideas) - Related issues/discussions are linked using `fixes #number` - e2e tests added (https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs) - Documentation added - Telemetry added. In case of a feature if it's used or not. - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ### Signed commits - This repository requires verified commit signatures on protected branches. - If this pull request is blocked for unsigned commits, re-sign the commits and force-push the branch. - A `Signed-off-by` line in the commit message is not enough. ## For Maintainers - Minimal description (aim for explaining to someone not on the team to understand the PR) - When linking to a Slack thread, you might want to share details of the conclusion - Link both the Linear (Fixes NEXT-xxx) and the GitHub issues - Add review comments if necessary to explain to the reviewer the logic behind a change ### What? Added the missing `pnpm` installation command to the `module-not-found` error documentation page. ### Why? To ensure consistency across the documentation, as other error pages and guides in Next.js typically include examples for npm, yarn, and pnpm. ### How? Added `- When using pnpm: pnpm add swr` to the "Possible Ways to Fix It" section in `errors/module-not-found.mdx`. Closes NEXT- Fixes # --> |
||
|
|
adb2913661 |
Stabilize export const prefetch (#94571)
This API is going to ship stable but some options may individually be marked unstable |
||
|
|
a9539183b8 |
Rename prefetch option force-runtime to allow-runtime (#94568)
While force-runtime does opt you into runtime prefetching today (i.e. it does force) the intended semantic is shifting to convey that the Segment itself is designed for and makes sense (i.e. cost / performance tradeoff) to runtime prefetch. In the future segments that may be runtime prefetched might not be for various optimization reasons. We therefore are renaming the option from force-runtime to allow-runtime. In the future if we change allow-runtime to sometimes not runtime prefetch we can always ship a new force-runtime as a codemod option that recovers the current behavior. This wording also better demonstrates why this is a feature of the Segment and not say an option on the link like `<Link prefetch="force-runtime" />`. |
||
|
|
2cc99c73b5 |
docs: move insight error pages from vercel/front to canary (#94564)
### What? Moves 14 insight-kind error pages from `vercel/front/apps/next-site/content/errors-extra/` into this repo's `errors/` directory. ### Why? `nextjs.org`'s sync pipeline already clones `errors/` from canary on every deploy. `errors-extra/` is meant for in-flight drafts. These pages have stabilized, so they belong with the framework code they describe. This unblocks Docs Link Validation in #94496: cross-links from this repo's API docs (`cookies.mdx`, `headers.mdx`, `use-params.mdx`, `use-pathname.mdx`, `generate-metadata.mdx`, `generate-viewport.mdx`, etc.) to `/docs/messages/blocking-prerender-*` now resolve. ### How? Copied each `.mdx` verbatim. No content changes. Frontmatter (`kind: insight`) routes them through the FixOption renderer. Follow-up PR in `vercel/front` will remove the `errors-extra/` copies; until then the override wins on slug collision but the content is byte-identical. <!-- NEXT_JS_LLM_PR --> |
||
|
|
2df0562f32 |
Specialize client hook prerender abort reasons (#94494)
Specialize Cache Components prerender abort errors for `useParams`, `usePathname`, `useSearchParams`, `useSelectedLayoutSegment`, and `useSelectedLayoutSegments` instead of reporting a generic abort reason. React now allows errors observed after abort begins but before the final abort task runs to replace the generic abort reason. Client hook promises can use this window to report which hook blocked prerendering while preserving higher-priority synchronous I/O errors. |
||
|
|
e2b0d2eadc |
Instant Insights: When unable to complete validation provide a filename for the unvalidated boundary (#93770)
The error message previously did not say which parallel route slot couldn't be validated. Now it poitns to the nearest segment below the validation boundary. The idea is you go look abive this and figure out if it is intentional that this segment isn't rendered in the current context. If so you can ignored the warning (it should ideally not even be presented as a normal error) but if it is unintentional you investigate why you aren't SSRing this slot or you mark the slot as intentionally blocking so it doesn't get validated. |
||
|
|
22fc63da72 |
docs: fix typos and links (#92541)
This PR cleans up small documentation and error-page issues: correct TypeScript spelling where it was written as “Typescript”, use the proper GitHub label in links, fix the MDN URL for `Map.prototype.values` in the middleware upgrade guide. No runtime or API behavior changes. |
||
|
|
215a08e2da |
Disable instant validations in draft mode (#93472)
This PR makes dev-mode cache bypass behavior consistent when `draftMode` is enabled. Draft mode now skips Instant Insights validation the same way a hard refresh or DevTools “Disable Cache” request does, and the Next.js devtools badge shows the existing “Cache disabled” state for draft-mode previews. It also adds coverage for draft-mode cache bypass behavior in dev and start modes, plus a devtools badge test, and updates the `cache-bypass-in-dev` docs to explain why draft mode triggers this state. |
||
|
|
d86e197728 |
Support configuring a default instant validation level (#93301)
Adds `experimental.instantInsights.validationLevel` so an app can opt into instant validation for all routes by default. There are two public levels * `manual-warning`: currently the default. this mode won't enable instant validation except where you add `export const unstable_instant = true` into your Layouts, Pages, and Default files * `warning`: This mode will enable instant validation for all Page and Default files. You can override this with `export const unstable_instant = false` in Layouts, Pages, and Default files to tune what navigations are validated. In addition this change disables build time validation. There is a now undocumented way to get back to running build validation with * `experimental-error` * `experimental-manual-error` The build validation isn't ready for users because we need to overhaul the setup where you provide cookies and other sample values so we can run validation without a live session like we do in dev. To further support this the two remaining object properties that are also not ready for active use, `samples` and `from` are being updated to `unstable_samples` and `unstable_from` respectively. We will continue to iterate on build time validation but may remove these APIs or alter their semantics as we figure out a more ergonomic way to support this setup. In anticipation of multiple levels the object form of `instant` can be provided a level value `warning` or `experimental-error`. this latter option is similarly undocumented so documented behavior will only cover `warning` which is generally a synonym of true unless you are activating error by default |
||
|
|
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> |
||
|
|
241ac2d62b |
New ESLint rule: no-location-assign-relative-destination (#92900)
## For Contributors ### Adding a feature Adding a new ESLint rule to `eslint-plugin-next` reporting `location.href = [relative URL]` or `location.assign([relative URL])` usage. For some reason, some LLM models prefer this incorrect pattern, and avoid `redirect()` or `useRouter().push()` at all costs. But at least many of them do respect ESLint, by adding a new rule we can enforce correct behavior. The error documentation and unit test cases are also added. --------- Co-authored-by: Joseph <sephxd1234@gmail.com> Co-authored-by: Benjamin Woodruff <benjamin.woodruff@vercel.com> |
||
|
|
219c0bcee9 |
docs: add documentation for no-typos ESLint rule (#92809)
## Summary The `@next/next/no-typos` rule ships in `@next/eslint-plugin-next` but has no corresponding page under `errors/`, so users who click through from ESLint config inspectors (or from other rule-docs links) hit a 404. This adds `errors/no-typos.mdx` describing: - What the rule catches (`getStaticProps` / `getStaticPaths` / `getServerSideProps`) - A standard before/after example - A **casing** example (since the rule uses a 1-char edit-distance threshold — casing typos like `getServerSideprops` also trip it) ## Context This re-attempts #89436 (closed, not merged) with @lukesandberg's two review comments applied: 1. **Title** shortened from *"No typos in Next.js data fetching functions"* → **"No Typos"**, matching other sibling rule docs in `errors/`. 2. **Casing example** now actually contains a casing error (`getServerSideprops`); the previous version listed `getServerSideProps` as "incorrect casing", which had no casing error. Fixes #67342 ## Test plan - [x] File lives under `errors/` alongside sibling rule docs (`no-document-import-in-page.mdx`, `no-unwanted-polyfillio.mdx`, etc.) - [x] Frontmatter + heading structure matches sibling docs - [x] Code fences use the same `filename=...` convention as sibling docs - [x] No manifest file under `errors/` — sibling additions (e.g. `no-unwanted-polyfillio.mdx`) did not touch an index |
||
|
|
053300c1fb |
docs: improve blocking-route error page for params discoverability (#92359)
### What?
Improves the `blocking-route` error doc (`errors/blocking-route.mdx`) to
make it easier to connect the "Uncached data was accessed outside of
`<Suspense>`" error to `await params` in a Page component.
### Why?
When a build fails with this error and the only callsite is `const { id
} = await params`, there's no indication that awaiting `params` directly
in a Page triggers it. The fix pattern (pass the `params` Promise to a
Suspense-wrapped child) exists in the doc under "Params and
SearchParams" but developers and AI agents won't find it without
`--debug-prerender` stack traces.
### How?
- Added a "common triggers" list to the "Why This Error Occurred"
section so developers can quickly pattern-match their code
- Added a `--debug-prerender` tip for getting detailed stack traces
- Added a concrete `params` before/after example showing the exact fix
pattern
- Listed all three fix options upfront: `<Suspense>` wrapping,
`loading.js`, or `generateStaticParams`
## PR checklist (Improving Documentation)
- [x] Run `pnpm prettier-fix` to fix formatting issues before opening
the PR
- [x] Follow the docs contribution guide:
https://nextjs.org/docs/community/contribution-guide
Made with [Cursor](https://cursor.com)
|
||
|
|
4f69336336 |
Support accessing root params in generateStaticParams (#91189)
A new `GenerateStaticParamsStore` work unit store type is now provided during `generateStaticParams` execution. This enables root param getters (`import { lang } from 'next/root-params'`) to be called inside `generateStaticParams`, allowing shared helpers that internally access root params via the special import to be used in both Server Components and `generateStaticParams` without manually threading params.
Each `generateStaticParams` call now runs within a `workUnitAsyncStorage.run()` context carrying a `GenerateStaticParamsStore` with the correct `rootParams` (extracted from `parentParams` using the already-available `rootParamKeys`). The store extends `CommonWorkUnitStore`, providing `phase` and `implicitTags` which are not strictly necessary but convenient to keep call sites simple.
Request-time APIs (`headers()`, `cookies()`, `connection()`, `draftMode()`) now throw specific errors when called inside `generateStaticParams` instead of the previous generic "called outside a request scope" message. Framework-internal functions like `createSearchParamsFromClient` and `createParamsFromClient` throw `InvariantError` since they should never be reached in this context.
This change also unblocks a follow-up PR that removes `| undefined` from `PublicCacheContext.outerWorkUnitStore` in the use cache wrapper, since `"use cache"` is already supported inside `generateStaticParams` today but previously ran without a `WorkUnitStore`. With this store in place, requiring a `WorkUnitStore` in `"use cache"` won't break that existing usage.
|
||
|
|
6155ca1722 |
docs: large page data error (#90920)
<!-- CURSOR_AGENT_PR_BODY_BEGIN --> <!-- Thanks for opening a PR! Your contribution is much appreciated. To make sure your PR is handled as smoothly as possible we request that you follow the checklist sections below. Choose the right checklist for the change(s) that you're making: ## For Contributors ### Improving Documentation - Run `pnpm prettier-fix` to fix formatting issues before opening the PR. - Read the Docs Contribution Guide to ensure your contribution follows the docs guidelines: https://nextjs.org/docs/community/contribution-guide ### Fixing a bug - Related issues linked using `fixes #number` - Tests added. See: https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ### Adding a feature - Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. (A discussion must be opened, see https://github.com/vercel/next.js/discussions/new?category=ideas) - Related issues/discussions are linked using `fixes #number` - e2e tests added (https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs) - Documentation added - Telemetry added. In case of a feature if it's used or not. - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ## For Maintainers - Minimal description (aim for explaining to someone not on the team to understand the PR) - When linking to a Slack thread, you might want to share details of the conclusion - Link both the Linear (Fixes NEXT-xxx) and the GitHub issues - Add review comments if necessary to explain to the reviewer the logic behind a change ### What? Improve the `errors/large-page-data.mdx` error page. ### Why? The existing error page lacked clarity on the `__NEXT_DATA__` mechanism, performance impacts, configuration options, and its applicability solely to the Pages Router. This led to confusion, as highlighted in community discussions: - https://github.com/vercel/next.js/discussions/38364#discussioncomment-3090327 - https://github.com/vercel/next.js/discussions/60193#discussioncomment-8010640 ### How? - Added a note clarifying this warning applies only to the Pages Router. - Explained the `__NEXT_DATA__` mechanism, why the threshold exists, and its performance implications (page weight, hydration, memory). - Provided actionable suggestions to reduce data size (filter, paginate, client-side fetching). - Documented the `experimental.largePageDataBytes` configuration option with a `next.config.js` example. - Included relevant external links for further reading. Closes NEXT- Fixes # --> --- [Slack Thread](https://vercel.slack.com/archives/C08N392Q9EV/p1772698459867909?thread_ts=1772698459.867909&cid=C08N392Q9EV) <p><a href="https://cursor.com/agents/bc-f75e35d4-cde9-5300-8c76-b4a67c24d55f"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-f75e35d4-cde9-5300-8c76-b4a67c24d55f"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </p> <!-- CURSOR_AGENT_PR_BODY_END --> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Joseph <icyJoseph@users.noreply.github.com> |
||
|
|
c2b4c0815c |
Unify caching story across the docs (#90149)
This PRs unifies the caching story across the docs, making Cache Components the happy path, while still providing guidance to users in the old model. However, instead of explaining the old model and its caching layers, we've created a new guide focusing on what APIs to use and when. This follow-up PR aligns terminology across the docs: https://github.com/vercel/next.js/pull/90589 ## IA updates Getting Started section: - Improves Getting Started progression: - **Before:** CC → Fetching Data → Updating Data → Caching and Revalidating (old and new model mixed) - **After:** Fetching Data (Dynamic) → Mutating Data (Dynamic) → Caching with CC (Prerendering) → Revalidating with CC. - New: `caching.mdx` (CC-first) - Structure: - Enabling Cache Components - Data vs UI-level caching - Working with request time APIs - Passing request values to cached functions - Working with non-deterministic operations - Working with synchronous operations - How rendering works (PPR and static shell story) - New: `revalidating.mdx` (CC-first) - Explains how to use `cacheLife` and `cacheTag` Guides Section: - New: `caching-and-revalidating.mdx` (Previous Model) - For users who are not using CC, includes `fetch` options and route segment config - Moves route segment config options that don't apply to CC from API reference to this guide (for easy archiving in the future). - New: `migrating-to-cache-components.mdx` (WIP) - Del: `caching.mdx` 😌 ## Terminology We should remove caching layers from the docs. Users only needed to be exposed to them when they were configured independently, but the new CC APIs work across layers. To make it easier to review this PR, I'm consolidating terminology and fixing broken links in a new PR: https://github.com/vercel/next.js/pull/90589 --------- Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com> Co-authored-by: Joseph <joseph.chamochumbi@vercel.com> |
||
|
|
5f26a684e6 |
docs: rework version staleness (#90192)
Closes: https://linear.app/vercel/issue/DOC-6144/error-page-version-staleness |
||
|
|
43c9a4915a |
docs: improve next/image localPatterns error page (#89914)
Align with https://nextjs.org/docs/messages/next-image-unconfigured-host Closes: https://linear.app/vercel/issue/DOC-5850/feedback-image-configuration-it-doesn-t-work-my-pattern-is-defined-as |
||
|
|
6627734522 |
docs: add deploymentId config and clarify encryption key for self-hosting (#89795)
Closes: https://linear.app/vercel/issue/DOC-3953/encryption-keys-in-server-actions, https://linear.app/vercel/issue/DOC-4975/next-server-actions-encryption-key-and-deploymentid Closes https://github.com/vercel/next.js/discussions/88327 --------- Co-authored-by: Allen Zhou <46854522+allenzhou101@users.noreply.github.com> |
||
|
|
be56ce3ae8 |
docs: correct use term (#89438)
### What? `use` is not a hook. It's highlighted in the doc > Unlike React Hooks, use can be called within loops and conditional statements like if. Like React Hooks, the function that calls use must be a Component or Hook. ### Why? It confuses consumers of Next.js and adds field provide misleading proofs ### How? Closes NEXT- Fixes # --> --------- Co-authored-by: Joseph <joseph.chamochumbi@vercel.com> Co-authored-by: Joseph <sephxd1234@gmail.com> |
||
|
|
2521b8adc7 |
[Instant] Instant validation in Dev (#89077)
This PR implements the initial version of dev-time validation for
`export const instant = ...`
```tsx
export const instant = { prefetch: 'static' }
```
```tsx
export const instant = { prefetch: 'runtime', ... }
```
```tsx
export const instant = false
```
(the config is currently expected to be named `unstable_instant`, but
i'll be shortening it to `instant` below.)
When a segment specifies an instant config with `prefetch: 'static'` or
`prefetch: 'runtime'`, we'll validate that all (prefetched) navigations
into that segment will render instant UI, i.e. that the navigation won't
block. On the other hand, if a segment is allowed to block, it must be
marked with `export const instant = false`.
Note that our existing static shell validation is a special case of
this, but for now, we're keeping both. A future PR will reimplement
static shell validation as a special case of instant validation.
Like static shell validation, these validations currently run in dev
whenever we render the full page (i.e. no segments are omitted). This
means it'll happen on an initial load (or refresh) and HMR.
### Implementation notes
#### Validation approach
The goal is to simulate what the browser would display for a prefetched
client navigation. We do this by re-assembling the segments extracted
from the original stream for the page.
- The outer (shared) segments should already fully resolved (i.e. in the
Dynamic stage), to represent the fact that the browser loaded them
before
- The new segments are either in Static or Runtime stage, depending on
how each segment would have been prefetched.
Similar to static shell validation, we then perform a Fizz prerender on
the combined payload, abort it, and track the locations of `onError`
calls. The difference here is that unlike static shell validation, we
require a Suspense boundary *inside* the new subtree. This is detected
by adding a `InstantValidationBoundary` around the new subtree when we
construct the payload, and checking if there's a suspense below that in
the component stack.
Currently, for each `instant` config we find, we take each of its parent
layouts as a possible navigation parent (unless it's marked as
blocking). So if we have a page with parent layouts like this:
```
/layout.tsx
/foo/layout.tsx
/foo/bar/layout.tsx
/foo/bar/page.tsx <- `export const instant = { prefetch: 'static' }`
```
Then we'll check for navigations where each of `/layout.tsx`,
`/foo/layout.tsx` and `/foo/bar/layout.tsx` is a fully resolved shared
parent.
If a validation fails, we do a "discriminated error message" flow
analogous to static shell validation. Static segments are replaced with
Runtime segments to see if the error goes away, which lets us determine
if the hole is caused by runtime or dynamic data.
#### Building the combined payload
First, we need to separate the full stream into segments. The process is
similar to `collectSegmentData` -- we need to deserialize the payload
from the stream and then re-serialize each segment separately. The
complexity here comes from the fact that the full stream is separated
into stages, and we need each segment to be in staged form as well. This
lets us pick and choose which stage the segment is in to simulate what
we'd show for a static or runtime prefetch.
The other complex part is the "late release trick" (as implemented in
`createNodeStreamWithLateRelease`). This was already done for static
shell validation, but it's more complex here.
Debug info for dynamic holes is usually delayed until a further stage.
So, in the static stage we only see an unresolved promise (or lazy
reference), and then in the runtime stage we get the debugInfo telling
us that it was caused by `await cookies()`. To ensure that this debug
info is available for purposes on error reporting, we do a "late
release" -- before we abort, we advance the each segment to the dynamic
stage, which won't cause any new content to render, but will provide
Fizz with debug info and thus give us precise error locations in
`onError`. If you see `releaseSignal`, that's what it's for.
#### `instant` on layouts
We support specifying `instant` on layouts. The validation principle is
the same, but note that in the current mode (validating a single page in
dev) we can't enforce that *all* navigations into that layout satisfy
the constraint, we can only check if that's satisfied for the current
page.
#### Blocking segments
A segment can be marked as blocking with
```tsx
export const instant = false
```
This is meant to signal that this segment deliberately does not have
instant UI.
Currently, this is affects validation as follows:
If there's no `instant` config in parent segments, skip validating all
navigations where this layout would be new (because we know it'd block),
i.e. only validate navigations where it's a shared parent. Children of
this segment can still have `instant` configs of their own, and those
will be validated. This allows structures where a layout is blocking,
but once it's loaded, navigations within it should have instant UI.
If there is an `instant` config in a parent segment, the validation of
that parent is *not* skipped. The reasoning here is that if a layout
asserts that navigations into it should have static UI, then a child
with `instant = false` should not violate that. This essentially
requires that the child have a `loading.js` or that the layout has to
wrap the slot with Suspense.
Note that `instant = false` can also be used to opt segements out of
static shell validation without requiring a Suspense above body.
### Limitations and planned follow-ups
- `instant` configs in parallel routes (i.e. `@slot`) are not currently
validated.
- `expectUnableToVerify` is not implemented yet, i.e. there's no way to
say "this cannot be validated using SSR". The shared segments are not
expected to suspend. For now, `export const instant = { prefetch: ...,
unstable_disableValidation: true }` can be used to bypass a segment if
validating it causes problems.
- static shell validation is a special case of instant validation, but
is not currently implemented as such.
- we should be able to validate during client navigations, not just
full-page loads and HMR, but we currently can't because we don't have
all the segments when we do that, so we can't assemble a proper combined
payload.
|
||
|
|
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 |