diff --git a/docs/01-app/02-guides/migrating-to-cache-components.mdx b/docs/01-app/02-guides/migrating-to-cache-components.mdx index 89ce06ffb9fa13..4937531ff3a32f 100644 --- a/docs/01-app/02-guides/migrating-to-cache-components.mdx +++ b/docs/01-app/02-guides/migrating-to-cache-components.mdx @@ -4,11 +4,11 @@ nav_title: Migrating to Cache Components description: Learn how to migrate from route segment configs to Cache Components in Next.js. --- -When [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents) is enabled, route segment configs like `dynamic`, `revalidate`, and `fetchCache` are replaced by [`use cache`](/docs/app/api-reference/directives/use-cache) and [`cacheLife`](/docs/app/api-reference/functions/cacheLife). +When [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents) is enabled, use [`use cache`](/docs/app/api-reference/directives/use-cache) and [`cacheLife`](/docs/app/api-reference/functions/cacheLife) instead of route segment configs like `dynamic`, `revalidate`, and `fetchCache`. ## `dynamic = "force-dynamic"` -**Not needed.** All pages are dynamic by default. +**Not needed.** Remove `export const dynamic = 'force-dynamic'`. When Cache Components is enabled, Next.js prerenders static segments and handles dynamic work during the request. The `force-dynamic` flag does not change that rendering path. ```tsx filename="app/page.tsx" switcher // Before - No longer needed @@ -29,14 +29,14 @@ export default function Page() { ``` ```tsx filename="app/page.tsx" switcher -// After - Just remove it +// After - Remove the export export default function Page() { return
...
} ``` ```jsx filename="app/page.js" switcher -// After - Just remove it +// After - Remove the export export default function Page() { return
...
} @@ -44,7 +44,7 @@ export default function Page() { ## `dynamic = "force-static"` -Start by removing it. When unhandled uncached or runtime data access is detected during development and build time, Next.js raises an error. Otherwise, the prerendering step automatically extracts the static HTML shell. +**Start by removing it.** When unhandled uncached or runtime data access is detected during development and build time, Next.js raises an error. Otherwise, the prerendering step automatically extracts the static HTML shell. For uncached data access, add [`use cache`](/docs/app/api-reference/directives/use-cache) as close to the data access as possible with a long [`cacheLife`](/docs/app/api-reference/functions/cacheLife) like `'max'` to maintain cached behavior. If needed, add it at the top of the page or layout. @@ -96,7 +96,7 @@ export default async function Page() { ## `revalidate` -**Replace with `cacheLife`.** Use the `cacheLife` function to define cache duration instead of the route segment config. +**Replace with `cacheLife`.** Use the [`cacheLife`](/docs/app/api-reference/functions/cacheLife) function with a [preset profile](/docs/app/api-reference/functions/cacheLife#using-preset-profiles) instead of the route segment config. For example, `revalidate = 3600` often lines up with the `'hours'` profile. Pick the profile that matches how often your data changes. ```tsx filename="app/page.tsx" switcher // Before @@ -170,6 +170,105 @@ export default async function Page() { } ``` +## `generateStaticParams` + +**Still supported.** [`generateStaticParams`](/docs/app/api-reference/functions/generate-static-params) works with [dynamic routes](/docs/app/api-reference/file-conventions/dynamic-routes) when Cache Components is enabled. + +**Different from before:** validation is stricter, unknown params are handled differently, and the `Route (app)` section from `next build` looks different. + +[`generateStaticParams` with Cache Components](/docs/app/api-reference/functions/generate-static-params#with-cache-components) covers Suspense, params you skip at build time, and the rest of the `generateStaticParams` contract. [Dynamic routes with Cache Components](/docs/app/api-reference/file-conventions/dynamic-routes#with-cache-components) covers routes that resolve `params` only at request time, including when you omit `generateStaticParams`. + +With Cache Components, Partial Prerendering applies to eligible routes, so returning `[]` from `generateStaticParams` triggers a [build error](/docs/messages/empty-generate-static-params). The build needs at least one path to validate the prerendered shell. Return at least one sample param (`After` below), or remove `generateStaticParams` and use the request-time patterns in [dynamic routes with Cache Components](/docs/app/api-reference/file-conventions/dynamic-routes#with-cache-components). + +```tsx filename="app/blog/[slug]/page.tsx" switcher +// Before +export async function generateStaticParams() { + return [] +} + +export default async function Page({ + params, +}: { + params: Promise<{ slug: string }> +}) { + const { slug } = await params + return
{slug}
+} +``` + +```jsx filename="app/blog/[slug]/page.js" switcher +// Before +export async function generateStaticParams() { + return [] +} + +export default async function Page({ params }) { + const { slug } = await params + return
{slug}
+} +``` + +```tsx filename="app/blog/[slug]/page.tsx" switcher +// After - Return at least one param (expand with your real slugs) +export async function generateStaticParams() { + return [{ slug: 'hello-world' }] +} + +export default async function Page({ + params, +}: { + params: Promise<{ slug: string }> +}) { + const { slug } = await params + return
{slug}
+} +``` + +```jsx filename="app/blog/[slug]/page.js" switcher +// After - Return at least one param (expand with your real slugs) +export async function generateStaticParams() { + return [{ slug: 'hello-world' }] +} + +export default async function Page({ params }) { + const { slug } = await params + return
{slug}
+} +``` + +With Cache Components enabled, [Partial Prerendering (PPR)](/docs/app/guides/public-static-pages#partial-prerendering) is the default for eligible routes, so the `Route (app)` section from `next build` reflects that model. Exact lines can differ slightly by Next.js version. The snippets below show a representative `/products/[id]` route with `generateStaticParams`. You may see **`◐` (Partial Prerender)** on the dynamic segment and **`○` (Static)** on prerendered param paths where you previously saw **`●` (SSG)**. + +**Before Cache Components:** + +```bash filename="Terminal" +Route (app) +┌ ○ / +├ ○ /_not-found +└ /products/[id] + ├ ● /products/1 + └ ● /products/2 + +○ (Static) prerendered as static content +● (SSG) prerendered as static HTML (uses generateStaticParams) +``` + +**With Cache Components:** + +```bash filename="Terminal" +Route (app) +┌ ○ / +├ ○ /_not-found +└ /products/[id] + ├ ◐ /products/[id] + ├ ○ /products/1 + └ ○ /products/2 + +○ (Static) prerendered as static content +◐ (Partial Prerender) prerendered as static HTML with dynamic server-streamed content +``` + +See [Building](/docs/app/guides/building) for more on `next build` output and symbols. + ## `runtime = 'edge'` **Not supported.** Cache Components requires the Node.js runtime. Switch to the Node.js runtime (the default) by removing the `runtime = 'edge'` export. If you need edge behavior for specific routes, use [Proxy](/docs/app/api-reference/file-conventions/proxy) instead.