From 90dd39db02a8e45781e71fd2645c0537a7c1646d Mon Sep 17 00:00:00 2001 From: mm Date: Fri, 4 Jul 2025 17:54:47 +0200 Subject: [PATCH 1/7] Update 06-partial-prerendering.mdx Updating the docs - the code for jsx and tsx versions should use the switcher --- docs/01-app/01-getting-started/06-partial-prerendering.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/01-app/01-getting-started/06-partial-prerendering.mdx b/docs/01-app/01-getting-started/06-partial-prerendering.mdx index e6ca866d1f5ac..8d4b776330b47 100644 --- a/docs/01-app/01-getting-started/06-partial-prerendering.mdx +++ b/docs/01-app/01-getting-started/06-partial-prerendering.mdx @@ -134,7 +134,7 @@ const nextConfig = { The `'incremental'` value allows you to adopt PPR for specific routes: -```tsx filename="/app/dashboard/layout.tsx" +```tsx filename="/app/dashboard/layout.tsx" switcher export const experimental_ppr = true export default function Layout({ children }: { children: React.ReactNode }) { @@ -142,7 +142,7 @@ export default function Layout({ children }: { children: React.ReactNode }) { } ``` -```jsx filename="/app/dashboard/layout.js" +```jsx filename="/app/dashboard/layout.jsx" switcher export const experimental_ppr = true export default function Layout({ children }) { From 034d3d2eeec6419efd6453688454e511d4e93830 Mon Sep 17 00:00:00 2001 From: MichalMoravik Date: Sun, 6 Jul 2025 19:05:55 +0200 Subject: [PATCH 2/7] ISR: fixing the docs example and its explanation --- .../incremental-static-regeneration.mdx | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/docs/01-app/02-guides/incremental-static-regeneration.mdx b/docs/01-app/02-guides/incremental-static-regeneration.mdx index 6609bbc5a9db1..3db2655f20bc9 100644 --- a/docs/01-app/02-guides/incremental-static-regeneration.mdx +++ b/docs/01-app/02-guides/incremental-static-regeneration.mdx @@ -38,13 +38,14 @@ export const revalidate = 60 // We'll prerender only the params from `generateStaticParams` at build time. // If a request comes in for a path that hasn't been generated, // Next.js will server-render the page on-demand. -export const dynamicParams = true // or false, to 404 on unknown paths +export const dynamicParams = true // setting to false will 404 on unknown paths instead export async function generateStaticParams() { const posts: Post[] = await fetch('https://api.vercel.app/blog').then((res) => res.json() ) - return posts.map((post) => ({ + // Generate params for 24 posts and leave 25th post for on-demand generation + return posts.slice(0, 24).map((post) => ({ id: String(post.id), })) } @@ -67,7 +68,7 @@ export default async function Page({ } ``` -```jsx filename="app/blog/[id]/page.js" switcher +```jsx filename="app/blog/[id]/page.jsx" switcher // Next.js will invalidate the cache when a // request comes in, at most once every 60 seconds. export const revalidate = 60 @@ -75,13 +76,14 @@ export const revalidate = 60 // We'll prerender only the params from `generateStaticParams` at build time. // If a request comes in for a path that hasn't been generated, // Next.js will server-render the page on-demand. -export const dynamicParams = true // or false, to 404 on unknown paths +export const dynamicParams = true // setting to false will 404 on unknown paths instead export async function generateStaticParams() { const posts = await fetch('https://api.vercel.app/blog').then((res) => res.json() ) - return posts.map((post) => ({ + // Generate params for 24 posts and leave 25th post for on-demand generation + return posts.slice(0, 24).map((post) => ({ id: String(post.id), })) } @@ -121,14 +123,14 @@ export const getStaticPaths: GetStaticPaths = async () => { const posts = await fetch('https://api.vercel.app/blog').then((res) => res.json() ) - const paths = posts.map((post: Post) => ({ + // Generate params for 24 posts and leave 25th post for on-demand generation + const paths = posts.slice(0, 24).map((post: Post) => ({ params: { id: String(post.id) }, })) - // We'll prerender only these paths at build time. - // { fallback: 'blocking' } will server-render pages - // on-demand if the path doesn't exist. - return { paths, fallback: false } + // If a request comes in for a path that hasn't been generated (e.g. /blog/25), + // Next.js will server-render the page on-demand. + return { paths, fallback: 'blocking' } // setting to false will 404 on unknown paths instead } export const getStaticProps: GetStaticProps = async ({ @@ -163,13 +165,14 @@ export async function getStaticPaths() { const posts = await fetch('https://api.vercel.app/blog').then((res) => res.json() ) - const paths = posts.map((post) => ({ + // Generate params for 24 posts and leave 25th post for on-demand generation + const paths = posts.slice(0, 24).map((post) => ({ params: { id: post.id }, })) - // We'll prerender only these paths at build time. - // { fallback: false } means other routes should 404. - return { paths, fallback: false } + // If a request comes in for a path that hasn't been generated (e.g. /blog/25), + // Next.js will server-render the page on-demand. + return { paths, fallback: 'blocking' } // setting to false will 404 on unknown paths instead } export async function getStaticProps({ params }) { @@ -199,12 +202,12 @@ export default function Page({ post }) { Here's how this example works: -1. During `next build`, all known blog posts are generated (there are 25 in this example) +1. During `next build`, the first 24 blog posts are generated (out of 25 available from the API) 2. All requests made to these pages (e.g. `/blog/1`) are cached and instantaneous 3. After 60 seconds has passed, the next request will still show the cached (stale) page 4. The cache is invalidated and a new version of the page begins generating in the background -5. Once generated successfully, Next.js will display and cache the updated page -6. If `/blog/26` is requested, Next.js will generate and cache this page on-demand +5. Once generated successfully, the next request will show the updated page +6. If `/blog/25` is requested (a post not generated at build time), the page will be generated on-demand, shown, and cached ## Reference From 55d7f510e52b2f1c528f7bc54dc478fa272b9093 Mon Sep 17 00:00:00 2001 From: MichalMoravik Date: Sun, 6 Jul 2025 19:31:36 +0200 Subject: [PATCH 3/7] Update Time-based revalidation section to be more clear on its workings --- docs/01-app/02-guides/incremental-static-regeneration.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/01-app/02-guides/incremental-static-regeneration.mdx b/docs/01-app/02-guides/incremental-static-regeneration.mdx index 3db2655f20bc9..923098262d951 100644 --- a/docs/01-app/02-guides/incremental-static-regeneration.mdx +++ b/docs/01-app/02-guides/incremental-static-regeneration.mdx @@ -240,7 +240,7 @@ Here's how this example works: ### Time-based revalidation -This fetches and displays a list of blog posts on `/blog`. After an hour, the cache for this page is invalidated on the next visit to the page. Then, in the background, a new version of the page is generated with the latest blog posts. +This fetches and displays a list of blog posts on /blog. After an hour has passed, the next visitor will still receive the cached (stale) version of the page immediately for a fast response. Simultaneously, Next.js triggers regeneration of a fresh version in the background. Once the new version is successfully generated, it replaces the cached version, and subsequent visitors will receive the updated content. ```tsx filename="app/blog/page.tsx" switcher interface Post { From f058c353a278d985bd0b0bcb30f1478207b1dd87 Mon Sep 17 00:00:00 2001 From: MichalMoravik Date: Sun, 6 Jul 2025 20:26:02 +0200 Subject: [PATCH 4/7] Being more clear for the on-demand revalidation --- docs/01-app/02-guides/incremental-static-regeneration.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/01-app/02-guides/incremental-static-regeneration.mdx b/docs/01-app/02-guides/incremental-static-regeneration.mdx index 923098262d951..0e787b51071e6 100644 --- a/docs/01-app/02-guides/incremental-static-regeneration.mdx +++ b/docs/01-app/02-guides/incremental-static-regeneration.mdx @@ -292,7 +292,7 @@ We recommend setting a high revalidation time. For instance, 1 hour instead of 1 For a more precise method of revalidation, invalidate pages on-demand with the `revalidatePath` function. -For example, this Server Action would get called after adding a new post. Regardless of how you retrieve your data in your Server Component, either using `fetch` or connecting to a database, this will clear the cache for the entire route and allow the Server Component to fetch fresh data. +For example, this Server Action would get called after adding a new post. Regardless of how you retrieve your data in your Server Component, either using `fetch` or connecting to a database, this will immediately clear the cache for the entire route. Unlike time-based revalidation, the next request won't return stale data but will serve the updated version right away and cache it for subsequent requests. ```ts filename="app/actions.ts" switcher 'use server' From bb2a7e4978e13813b366afaee6e54450d8f40a03 Mon Sep 17 00:00:00 2001 From: MichalMoravik Date: Sun, 6 Jul 2025 20:28:39 +0200 Subject: [PATCH 5/7] Updating on-demand revalidation with even more clarification --- docs/01-app/02-guides/incremental-static-regeneration.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/01-app/02-guides/incremental-static-regeneration.mdx b/docs/01-app/02-guides/incremental-static-regeneration.mdx index 0e787b51071e6..1b50a7add3db9 100644 --- a/docs/01-app/02-guides/incremental-static-regeneration.mdx +++ b/docs/01-app/02-guides/incremental-static-regeneration.mdx @@ -292,7 +292,7 @@ We recommend setting a high revalidation time. For instance, 1 hour instead of 1 For a more precise method of revalidation, invalidate pages on-demand with the `revalidatePath` function. -For example, this Server Action would get called after adding a new post. Regardless of how you retrieve your data in your Server Component, either using `fetch` or connecting to a database, this will immediately clear the cache for the entire route. Unlike time-based revalidation, the next request won't return stale data but will serve the updated version right away and cache it for subsequent requests. +For example, this Server Action would get called after adding a new post. Regardless of how you retrieve your data in your Server Component, either using `fetch` or connecting to a database, this will immediately clear the cache for the entire route. Unlike time-based revalidation, the next request after on-demand revalidation won't return stale data but will serve the updated version right away and cache it for subsequent requests. ```ts filename="app/actions.ts" switcher 'use server' From 7345d84c96641bcf04e93bed5d995a2e91a3f129 Mon Sep 17 00:00:00 2001 From: MichalMoravik Date: Thu, 10 Jul 2025 10:11:47 +0200 Subject: [PATCH 6/7] Adding the 404 dynamicParams note to the 6th description point, removing from the code example --- .../02-guides/incremental-static-regeneration.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/01-app/02-guides/incremental-static-regeneration.mdx b/docs/01-app/02-guides/incremental-static-regeneration.mdx index 1b50a7add3db9..dd9bfe9a8c2be 100644 --- a/docs/01-app/02-guides/incremental-static-regeneration.mdx +++ b/docs/01-app/02-guides/incremental-static-regeneration.mdx @@ -38,7 +38,7 @@ export const revalidate = 60 // We'll prerender only the params from `generateStaticParams` at build time. // If a request comes in for a path that hasn't been generated, // Next.js will server-render the page on-demand. -export const dynamicParams = true // setting to false will 404 on unknown paths instead +export const dynamicParams = true export async function generateStaticParams() { const posts: Post[] = await fetch('https://api.vercel.app/blog').then((res) => @@ -76,7 +76,7 @@ export const revalidate = 60 // We'll prerender only the params from `generateStaticParams` at build time. // If a request comes in for a path that hasn't been generated, // Next.js will server-render the page on-demand. -export const dynamicParams = true // setting to false will 404 on unknown paths instead +export const dynamicParams = true export async function generateStaticParams() { const posts = await fetch('https://api.vercel.app/blog').then((res) => @@ -130,7 +130,7 @@ export const getStaticPaths: GetStaticPaths = async () => { // If a request comes in for a path that hasn't been generated (e.g. /blog/25), // Next.js will server-render the page on-demand. - return { paths, fallback: 'blocking' } // setting to false will 404 on unknown paths instead + return { paths, fallback: 'blocking' } } export const getStaticProps: GetStaticProps = async ({ @@ -172,7 +172,7 @@ export async function getStaticPaths() { // If a request comes in for a path that hasn't been generated (e.g. /blog/25), // Next.js will server-render the page on-demand. - return { paths, fallback: 'blocking' } // setting to false will 404 on unknown paths instead + return { paths, fallback: 'blocking' } } export async function getStaticProps({ params }) { @@ -207,7 +207,7 @@ Here's how this example works: 3. After 60 seconds has passed, the next request will still show the cached (stale) page 4. The cache is invalidated and a new version of the page begins generating in the background 5. Once generated successfully, the next request will show the updated page -6. If `/blog/25` is requested (a post not generated at build time), the page will be generated on-demand, shown, and cached +6. If `/blog/25` is requested (a post not generated at build time), the page will be generated on-demand, shown, and cached. If `dynamicParams` was set to `false`, the page would 404 instead. ## Reference From 730f33678f6153faeca69111c226d8f428c436fa Mon Sep 17 00:00:00 2001 From: MichalMoravik Date: Tue, 15 Jul 2025 11:36:51 +0200 Subject: [PATCH 7/7] ISR guide update - removing some parts from the code example and streamlining the description underneath the example --- .../incremental-static-regeneration.mdx | 47 ++++++++----------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/docs/01-app/02-guides/incremental-static-regeneration.mdx b/docs/01-app/02-guides/incremental-static-regeneration.mdx index dd9bfe9a8c2be..bca3d8859a7ef 100644 --- a/docs/01-app/02-guides/incremental-static-regeneration.mdx +++ b/docs/01-app/02-guides/incremental-static-regeneration.mdx @@ -35,17 +35,11 @@ interface Post { // request comes in, at most once every 60 seconds. export const revalidate = 60 -// We'll prerender only the params from `generateStaticParams` at build time. -// If a request comes in for a path that hasn't been generated, -// Next.js will server-render the page on-demand. -export const dynamicParams = true - export async function generateStaticParams() { const posts: Post[] = await fetch('https://api.vercel.app/blog').then((res) => res.json() ) - // Generate params for 24 posts and leave 25th post for on-demand generation - return posts.slice(0, 24).map((post) => ({ + return posts.map((post) => ({ id: String(post.id), })) } @@ -73,17 +67,11 @@ export default async function Page({ // request comes in, at most once every 60 seconds. export const revalidate = 60 -// We'll prerender only the params from `generateStaticParams` at build time. -// If a request comes in for a path that hasn't been generated, -// Next.js will server-render the page on-demand. -export const dynamicParams = true - export async function generateStaticParams() { const posts = await fetch('https://api.vercel.app/blog').then((res) => res.json() ) - // Generate params for 24 posts and leave 25th post for on-demand generation - return posts.slice(0, 24).map((post) => ({ + return posts.map((post) => ({ id: String(post.id), })) } @@ -102,6 +90,15 @@ export default async function Page({ params }) { } ``` +Here's how this example works: + +1. During `next build`, all known blog posts are generated +2. All requests made to these pages (e.g. `/blog/1`) are cached and instantaneous +3. After 60 seconds has passed, the next request will still return the cached (now stale) page +4. The cache is invalidated and a new version of the page begins generating in the background +5. Once generated successfully, the next request will return the updated page and cache it for subsequent requests +6. If `/blog/26` is requested, and it exists, the page will be generated on-demand. This behavior can be changed by using a different [dynamicParams](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamicparams) value. However, if the post does not exist, then 404 is returned. + @@ -123,13 +120,10 @@ export const getStaticPaths: GetStaticPaths = async () => { const posts = await fetch('https://api.vercel.app/blog').then((res) => res.json() ) - // Generate params for 24 posts and leave 25th post for on-demand generation - const paths = posts.slice(0, 24).map((post: Post) => ({ + const paths = posts.map((post: Post) => ({ params: { id: String(post.id) }, })) - // If a request comes in for a path that hasn't been generated (e.g. /blog/25), - // Next.js will server-render the page on-demand. return { paths, fallback: 'blocking' } } @@ -165,13 +159,10 @@ export async function getStaticPaths() { const posts = await fetch('https://api.vercel.app/blog').then((res) => res.json() ) - // Generate params for 24 posts and leave 25th post for on-demand generation - const paths = posts.slice(0, 24).map((post) => ({ + const paths = posts.map((post) => ({ params: { id: post.id }, })) - // If a request comes in for a path that hasn't been generated (e.g. /blog/25), - // Next.js will server-render the page on-demand. return { paths, fallback: 'blocking' } } @@ -198,16 +189,16 @@ export default function Page({ post }) { } ``` - - Here's how this example works: -1. During `next build`, the first 24 blog posts are generated (out of 25 available from the API) +1. During `next build`, all known blog posts are generated 2. All requests made to these pages (e.g. `/blog/1`) are cached and instantaneous -3. After 60 seconds has passed, the next request will still show the cached (stale) page +3. After 60 seconds has passed, the next request will still return the cached (now stale) page 4. The cache is invalidated and a new version of the page begins generating in the background -5. Once generated successfully, the next request will show the updated page -6. If `/blog/25` is requested (a post not generated at build time), the page will be generated on-demand, shown, and cached. If `dynamicParams` was set to `false`, the page would 404 instead. +5. Once generated successfully, the next request will return the updated page and cache it for subsequent requests +6. If `/blog/26` is requested, and it exists, the page will be generated on-demand. This behavior can be changed by using a different [fallback](https://nextjs.org/docs/pages/api-reference/functions/get-static-paths#fallback-false) value. However, if the post does not exist, then 404 is returned. + + ## Reference