Next.js allows you to create or update static pages after you’ve built your site. Incremental Static Regeneration (ISR) enables developers and content editors to use static-generation on a per-page basis, without needing to rebuild the entire site. With ISR, you can retain the benefits of static while scaling to millions of pages.
Static pages can be generated at runtime (on-demand) instead of at build-time with ISR. Using analytics, A/B testing, or other metrics, you are equipped with the flexibility to make your own tradeoff on build times.
Consider the e-commerce store from before with 100,000 products. At a realistic 50ms to statically generate each product page, this would take almost 2 hours without ISR. With ISR, we can choose from:
Faster Builds: Generate the most popular 1,000 products at build-time. Requests made to other products will be a cache miss and statically generate on-demand: 1-minute builds.
Higher Cache Hit Rate: Generate 10,000 products at build-time, ensuring more products are cached ahead of a user’s request: 8-minute builds.
Data Fetching
Next.js uses a combination of static generation and server-side regeneration to implement ISR. When a user requests a page:
- If the page exists in the cache and hasn’t exceeded the revalidation time, the static page is served.
- If the revalidation time has passed, a new version of the page is fetched and generated in the background.
- Subsequent users will see the newly updated page after it has been regenerated.
- Next.js can define a revalidation time per page. Let’s set it at 60 seconds.
- The initial request to the product page will show the cached page with the original price.
- The data for the product is updated in the CMS.
- Any requests to the page after the initial request and before 60 seconds are cached and instantaneous.
- After the 60-second window, the next request will still show the cached (stale) page. Next.js triggers a regeneration of the page in the background.
- Once the page has been successfully generated, Next.js will invalidate the cache and show the updated product page. If the background regeneration fails, the old page remains unaltered.
Implementing ISR in Nexjs
For Page Router: The Page Router was the default in Next.js until version 13 introduced the App Router. In this router, ISR is implemented by using the getStaticProps function within a page component.
import { GetStaticPaths, GetStaticProps } from 'next'
interface Post {
id: string
title: string
content: string
}
interface Props {
post: Post
}
export const getStaticPaths: GetStaticPaths = async () => {
const posts = await fetch('https://api.vercel.app/blog').then((res) =>
res.json()
)
const paths = posts.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 }
}
export const getStaticProps: GetStaticProps<Props> = async ({
params,
}: {
params: { id: string }
}) => {
let post = await fetch(`https://api.vercel.app/blog/${params.id}`).then(
(res) => res.json()
)
return {
props: { post },
// Next.js will invalidate the cache when a
// request comes in, at most once every 60 seconds.
revalidate: 60,
}
}
export default function Page({ post }: Props) {
return (
<main>
<h1>{post.title}</h1>
<p>{post.content}</p>
</main>
)
}
Key Points:
- getStaticProps: Fetches the data for the page. By returning a revalidate key, Next.js regenerates the page in the background every 10 seconds.
- getStaticPaths: Tells Next.js which pages to statically generate at build time. The fallback: 'blocking' option ensures that if a user requests a page that isn’t generated yet, it will be rendered on demand.
For App Router(Nextjs recommend use App router): Next.js 13 introduced the App Router, which is a new way of defining routes and data fetching. The App Router uses React Server Components (RSC) and provides better flexibility and ergonomics. With the App Router, ISR is implemented using the fetch function with caching options.
interface Post {
id: string
title: string
content: string
}
// Next.js will invalidate the cache when a
// 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 // or false, to 404 on unknown paths
export async function generateStaticParams() {
const posts: Post[] = await fetch('https://api.vercel.app/blog').then((res) =>
res.json()
)
return posts.map((post) => ({
id: String(post.id),
}))
}
export default async function Page({ params }: { params: { id: string } }) {
const post = await fetch(`https://api.vercel.app/blog/${params.id}`).then(
(res) => res.json()
)
return (
<main>
<h1>{post.title}</h1>
<p>{post.content}</p>
</main>
)
}
Key Points:
- generateStaticParams: Pre-generates static parameters for the route (similar to getStaticPaths). It helps Next.js know which pages to statically generate at build time.
- fetch with next.revalidate: This is where ISR happens in the App Router. The revalidate option in fetch tells Next.js to revalidate the data and regenerate the static page every 60 seconds.
Here is how the above 2 code snippets work:
- During next build, all known blog posts are generated (there are 1000 product).
- All requests made to these pages (e.g. /blog/1) are cached and instantaneous.
- After 60 seconds has passed, the next request will still show the cached (stale) page.
- The cache is invalidated and a new version of the page begins generating in the background.
- Once generated successfully, Next.js will display and cache the updated page.
- If /blog/1001 is requested, Next.js will generate and cache this page on-demand.
When Should You Use ISR?
Incremental Static Regeneration (ISR) is a great solution for scenarios where you need a balance between the speed of static sites and the need for fresh, updated content. Here are some key situations where ISR shines:
- Content Changes Regularly, But Not in Real-Time ISR is perfect for content that needs periodic updates but doesn't require real-time accuracy.
- Avoiding Full Rebuilds on Content Changes: For websites with frequently changing content, rebuilding the entire site on every content change is inefficient. ISR allows you to update only specific pages when necessary, significantly reducing the need for full site rebuilds.
- Improving SEO with Updated Content: Search engines favor pages that are frequently updated, and ISR allows static pages to be regenerated with fresh content, improving SEO. This ensures that the pages remain relevant and that search engines are indexing up-to-date content.
When Not to Use ISR
Real-Time Applications: If your application requires real-time data updates (such as live sports scores, chat applications, or stock trading platforms), ISR might not be the best choice. Instead, consider using server-side rendering (SSR) or client-side fetching for real-time data updates.
Highly Dynamic Data: If the data on your site changes every second (e.g., stock prices, cryptocurrency rates), ISR’s scheduled revalidation might not keep up. In these cases, SSR or client-side fetching is a better fit.
Conclusion
ISR is a powerful tool when you need a balance between static performance and dynamic updates. It is best used when your content changes on a regular, but not real-time, basis. Whether you're building product pages, blogs, or large-scale content sites, ISR allows you to keep your pages fresh and responsive without sacrificing performance or scalability. Use ISR when you want to give your users fast, static pages with the confidence that content will be up-to-date in the background.
Top comments (0)