Note that we also added the getStaticPaths function to generat

API RoutesIntroductionDynamic API RoutesRequest HelpersResponse HelpersEdge API RoutesGoing to ProductionDeploymentAuthenticationTestingAccessibilityGuidesBuilding FormsAdvanced FeaturesNext.js CompilerTurbopackPreview ModeDynamic ImportAutomatic Static OptimizationStatic HTML ExportAbsolute Imports and Module Path AliasesUsing MDXAMP SupportIntroductionAdding AMP ComponentsAMP ValidationAMP in Static HTML exportTypeScriptCustomizing Babel ConfigCustomizing PostCSS ConfigCustom ServerCustom `App`Custom `Document`Custom Error Page`src` DirectoryCI Build CachingMulti ZonesMeasuring performanceMiddlewareDebuggingError HandlingSource MapsCodemodsInternationalized RoutingOutput File TracingInstrumentationOpen TelemetrySecurity HeadersReact 18OverviewStreaming SSRReact Server ComponentsSwitchable RuntimeUpgrade GuideMigrating to Next.jsIncrementally Adopting Next.jsMigrating from GatsbyMigrating from Create React AppMigrating from React RouterFAQ

API Reference

CLICreate Next Appnext/routernext/linknext/imagenext/scriptnext/headnext/ampnext/servernext/fontnext/legacy/imageEdge RuntimeData FetchinggetInitialPropsgetServerSidePropsgetStaticPathsgetStaticPropsStatic Optimization Indicatornext.config.jsIntroductionEnvironment VariablesBase PathRewritesRedirectsCustom HeadersCustom Page ExtensionsCDN Support with Asset PrefixCustom Image Loader ConfigCustom Webpack ConfigCompressionRuntime ConfigurationDisabling x-powered-byDisabling ETag GenerationDisabling HTTP Keep-AliveSetting a custom build directoryConfiguring the Build IDConfiguring onDemandEntriesIgnoring ESLintIgnoring TypeScript ErrorsexportPathMapTrailing SlashReact Strict ModeURL ImportsBuild indicatorTurbopack-specific options

getStaticProps

If you export a function called getStaticProps (Static Site Generation) from a page, Next.js will pre-render this page at build time using the props returned by getStaticProps.

export async function getStaticProps(context) { return { props: {}, // will be passed to the page component as props } }

Note that irrespective of rendering type, any props will be passed to the page component and can be viewed on the client-side in the initial HTML. This is to allow the page to be hydrated correctly. Make sure that you don't pass any sensitive information that shouldn't be available on the client in props.

When should I use getStaticProps?

You should use getStaticProps if:

  • The data required to render the page is available at build time ahead of a user’s request
  • The data comes from a headless CMS
  • The page must be pre-rendered (for SEO) and be very fast — getStaticProps generates HTML and JSON files, both of which can be cached by a CDN for performance
  • The data can be publicly cached (not user-specific). This condition can be bypassed in certain specific situation by using a Middleware to rewrite the path.

When does getStaticProps run

getStaticProps always runs on the server and never on the client. You can validate code written inside getStaticProps is removed from the client-side bundle with this tool.

  • getStaticProps always runs during next build
  • getStaticProps runs in the background when using fallback: true
  • getStaticProps is called before initial render when using fallback: blocking
  • getStaticProps runs in the background when using revalidate
  • getStaticProps runs on-demand in the background when using revalidate()

When combined with Incremental Static Regeneration, getStaticProps will run in the background while the stale page is being revalidated, and the fresh page served to the browser.

getStaticProps does not have access to the incoming request (such as query parameters or HTTP headers) as it generates static HTML. If you need access to the request for your page, consider using Middleware in addition to getStaticProps.

Using getStaticProps to fetch data from a CMS

The following example shows how you can fetch a list of blog posts from a CMS.

// posts will be populated at build time by getStaticProps() function Blog({ posts }) { return ( <ul>{posts.map((post) => ( <li>{post.title}</li> ))}</ul> ) } // This function gets called at build time on server-side. // It won't be called on client-side, so you can even do // direct database queries. export async function getStaticProps() { // Call an external API endpoint to get posts. // You can use any data fetching library const res = await fetch('https://.../posts') const posts = await res.json() // By returning { props: { posts } }, the Blog component // will receive `posts` as a prop at build time return { props: { posts, }, } } export default Blog

The getStaticProps API reference covers all parameters and props that can be used with getStaticProps.

Write server-side code directly

As getStaticProps runs only on the server-side, it will never run on the client-side. It won’t even be included in the JS bundle for the browser, so you can write direct database queries without them being sent to browsers.

This means that instead of fetching an API route from getStaticProps (that itself fetches data from an external source), you can write the server-side code directly in getStaticProps.

Take the following example. An API route is used to fetch some data from a CMS. That API route is then called directly from getStaticProps. This produces an additional call, reducing performance. Instead, the logic for fetching the data from the CMS can be shared by using a lib/ directory. Then it can be shared with getStaticProps.

// lib/load-posts.js // The following function is shared // with getStaticProps and API routes // from a `lib/` directory export async function loadPosts() { // Call an external API endpoint to get posts const res = await fetch('https://.../posts/') const data = await res.json() return data } // pages/blog.js import { loadPosts } from '../lib/load-posts' // This function runs only on the server side export async function getStaticProps() { // Instead of fetching your `/api` route you can call the same // function directly in `getStaticProps` const posts = await loadPosts() // Props returned will be passed to the page component return { props: { posts } } }

Alternatively, if you are not using API routes to fetch data, then the fetch() API can be used directly in getStaticProps to fetch data.

To verify what Next.js eliminates from the client-side bundle, you can use the next-code-elimination tool.

Statically generates both HTML and JSON

When a page with getStaticProps is pre-rendered at build time, in addition to the page HTML file, Next.js generates a JSON file holding the result of running getStaticProps.

This JSON file will be used in client-side routing through next/link or next/router. When you navigate to a page that’s pre-rendered using getStaticProps, Next.js fetches this JSON file (pre-computed at build time) and uses it as the props for the page component. This means that client-side page transitions will not call getStaticProps as only the exported JSON is used.

When using Incremental Static Generation, getStaticProps will be executed in the background to generate the JSON needed for client-side navigation. You may see this in the form of multiple requests being made for the same page, however, this is intended and has no impact on end-user performance.

Where can I use getStaticProps

getStaticProps can only be exported from a page. You cannot export it from non-page files, _app, _document, or _error.

One of the reasons for this restriction is that React needs to have all the required data before the page is rendered.

Also, you must use export getStaticProps as a standalone function — it will not work if you add getStaticProps as a property of the page component.

Note: if you have created a custom app, ensure you are passing the pageProps to the page component as shown in the linked document, otherwise the props will be empty.

Runs on every request in development

In development (next dev), getStaticProps will be called on every request.

Preview Mode

You can temporarily bypass static generation and render the page at request time instead of build time using Preview Mode. For example, you might be using a headless CMS and want to preview drafts before they're published.

Related

For more information on what to do next, we recommend the following sections:

getStaticProps API Reference

Read the API Reference for getStaticPropsgetServerSidePropsgetStaticPaths

Was this helpful?

EMAILFEEDBACKEdit this page on GitHub

Skip to contentShowcaseDocsBlogAnalyticsTemplatesEnterpriseFeedbackLearn

Documentation

Getting StartedBasic FeaturesPagesData FetchingOverviewgetServerSidePropsgetStaticPropsgetStaticPathsIncremental Static RegenerationClient sideBuilt-in CSS SupportLayoutsImage OptimizationFont OptimizationStatic File ServingFast RefreshESLintTypeScriptEnvironment VariablesSupported Browsers and FeaturesHandling ScriptsRoutingIntroductionDynamic RoutesImperativelyShallow RoutingAPI RoutesIntroductionDynamic API RoutesRequest HelpersResponse HelpersEdge API RoutesGoing to ProductionDeploymentAuthenticationTestingAccessibilityGuidesBuilding FormsAdvanced FeaturesNext.js CompilerTurbopackPreview ModeDynamic ImportAutomatic Static OptimizationStatic HTML ExportAbsolute Imports and Module Path AliasesUsing MDXAMP SupportIntroductionAdding AMP ComponentsAMP ValidationAMP in Static HTML exportTypeScriptCustomizing Babel ConfigCustomizing PostCSS ConfigCustom ServerCustom `App`Custom `Document`Custom Error Page`src` DirectoryCI Build CachingMulti ZonesMeasuring performanceMiddlewareDebuggingError HandlingSource MapsCodemodsInternationalized RoutingOutput File TracingInstrumentationOpen TelemetrySecurity HeadersReact 18OverviewStreaming SSRReact Server ComponentsSwitchable RuntimeUpgrade GuideMigrating to Next.jsIncrementally Adopting Next.jsMigrating from GatsbyMigrating from Create React AppMigrating from React RouterFAQ

API Reference

CLICreate Next Appnext/routernext/linknext/imagenext/scriptnext/headnext/ampnext/servernext/fontnext/legacy/imageEdge RuntimeData FetchinggetInitialPropsgetServerSidePropsgetStaticPathsgetStaticPropsStatic Optimization Indicatornext.config.jsIntroductionEnvironment VariablesBase PathRewritesRedirectsCustom HeadersCustom Page ExtensionsCDN Support with Asset PrefixCustom Image Loader ConfigCustom Webpack ConfigCompressionRuntime ConfigurationDisabling x-powered-byDisabling ETag GenerationDisabling HTTP Keep-AliveSetting a custom build directoryConfiguring the Build IDConfiguring onDemandEntriesIgnoring ESLintIgnoring TypeScript ErrorsexportPathMapTrailing SlashReact Strict ModeURL ImportsBuild indicatorTurbopack-specific options

Incremental Static Regeneration

Examples

Version History

Next.js allows you to create or update static pages after you’ve built your site. Incremental Static Regeneration (ISR) enables you 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.

Note: The experimental-edge runtime is currently not compatible with ISR, although you can leverage stale-while-revalidate by setting the cache-control header manually.

To use ISR, add the revalidate prop to getStaticProps:

function Blog({ posts }) { return ( <ul>{posts.map((post) => ( <li key={post.id}>{post.title}</li> ))}</ul> ) } // This function gets called at build time on server-side. // It may be called again, on a serverless function, if // revalidation is enabled and a new request comes in export async function getStaticProps() { const res = await fetch('https://.../posts') const posts = await res.json() return { props: { posts, }, // Next.js will attempt to re-generate the page: // - When a request comes in // - At most once every 10 seconds revalidate: 10, // In seconds } } // This function gets called at build time on server-side. // It may be called again, on a serverless function, if // the path has not been generated. export async function getStaticPaths() { const res = await fetch('https://.../posts') const posts = await res.json() // Get the paths we want to pre-render based on posts const paths = posts.map((post) => ({ params: { id: post.id }, })) // We'll pre-render only these paths at build time. // { fallback: 'blocking' } will server-render pages // on-demand if the path doesn't exist. return { paths, fallback: 'blocking' } } export default Blog

When a request is made to a page that was pre-rendered at build time, it will initially show the cached page.

  • Any requests to the page after the initial request and before 10 seconds are also cached and instantaneous.
  • After the 10-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 generates successfully, Next.js will invalidate the cache and show the updated page. If the background regeneration fails, the old page would still be unaltered.

When a request is made to a path that hasn’t been generated, Next.js will server-render the page on the first request. Future requests will serve the static file from the cache. ISR on Vercel persists the cache globally and handles rollbacks.

Note: Check if your upstream data provider has caching enabled by default. You might need to disable (e.g. useCdn: false), otherwise a revalidation won't be able to pull fresh data to update the ISR cache. Caching can occur at a CDN (for an endpoint being requested) when it returns the Cache-Control header.

On-Demand Revalidation

If you set a revalidate time of 60, all visitors will see the same generated version of your site for one minute. The only way to invalidate the cache is from someone visiting that page after the minute has passed.

Starting with v12.2.0, Next.js supports On-Demand Incremental Static Regeneration to manually purge the Next.js cache for a specific page. This makes it easier to update your site when:

  • Content from your headless CMS is created or updated
  • Ecommerce metadata changes (price, description, category, reviews, etc.)

Inside getStaticProps, you do not need to specify revalidate to use on-demand revalidation. If revalidate is omitted, Next.js will use the default value of false (no revalidation) and only revalidate the page on-demand when revalidate() is called.

Note: Middleware won't be executed for On-Demand ISR requests. Instead, call revalidate() on the exact path that you want revalidated. For example, if you have pages/blog/[slug].js and a rewrite from /post-1 -> /blog/post-1, you would need to call res.revalidate('/blog/post-1').

Using On-Demand Revalidation

First, create a secret token only known by your Next.js app. This secret will be used to prevent unauthorized access to the revalidation API Route. You can access the route (either manually or with a webhook) with the following URL structure:

https://<your-site.com>/api/revalidate?secret=<token>

Next, add the secret as an Environment Variable to your application. Finally, create the revalidation API Route:

// pages/api/revalidate.js export default async function handler(req, res) { // Check for secret to confirm this is a valid request if (req.query.secret !== process.env.MY_SECRET_TOKEN) { return res.status(401).json({ message: 'Invalid token' }) } try { // this should be the actual path not a rewritten path // e.g. for "/blog/[slug]" this should be "/blog/post-1" await res.revalidate('/path-to-revalidate') return res.json({ revalidated: true }) } catch (err) { // If there was an error, Next.js will continue // to show the last successfully generated page return res.status(500).send('Error revalidating') } }

View our demo to see on-demand revalidation in action and provide feedback.

Testing on-Demand ISR during development

When running locally with next dev, getStaticProps is invoked on every request. To verify your on-demand ISR configuration is correct, you will need to create a production build and start the production server:

$ next build $ next start

Then, you can confirm that static pages have successfully revalidated.

Error handling and revalidation

If there is an error inside getStaticProps when handling background regeneration, or you manually throw an error, the last successfully generated page will continue to show. On the next subsequent request, Next.js will retry calling getStaticProps.

export async function getStaticProps() { // If this request throws an uncaught error, Next.js will // not invalidate the currently shown page and // retry getStaticProps on the next request. const res = await fetch('https://.../posts') const posts = await res.json() if (!res.ok) { // If there is a server error, you might want to // throw an error instead of returning so that the cache is not updated // until the next successful request. throw new Error(`Failed to fetch posts, received status ${res.status}`) } // If the request was successful, return the posts // and revalidate every 10 seconds. return { props: { posts, }, revalidate: 10, } }

Self-hosting ISR

Incremental Static Regeneration (ISR) works on self-hosted Next.js sites out of the box when you use next start.

You can use this approach when deploying to container orchestrators such as Kubernetes or HashiCorp Nomad. By default, generated assets will be stored in-memory on each pod. This means that each pod will have its own copy of the static files. Stale data may be shown until that specific pod is hit by a request.

To ensure consistency across all pods, you can disable in-memory caching. This will inform the Next.js server to only leverage assets generated by ISR in the file system.

You can use a shared network mount in your Kubernetes pods (or similar setup) to reuse the same file-system cache between different containers. By sharing the same mount, the .next folder which contains the next/image cache will also be shared and re-used.

To disable in-memory caching, set isrMemoryCacheSize to 0 in your next.config.js file:

module.exports = { experimental: { // Defaults to 50MB isrMemoryCacheSize: 0, }, }

Note: You might need to consider a race condition between multiple pods trying to update the cache at the same time, depending on how your shared mount is configured.

Related

For more information on what to do next, we recommend the following sections:

Dynamic routing

Learn more about dynamic routing in Next.js with getStaticPaths.getStaticPathsClient side

Was this helpful?

EMAILFEEDBACKEdit this page on GitHub

Data Fetching: Incremental Static Regeneration | Next.js

Skip to contentShowcaseDocsBlogAnalyticsTemplatesEnterpriseFeedbackLearn

Documentation

Getting StartedBasic FeaturesPagesData FetchingOverviewgetServerSidePropsgetStaticPropsgetStaticPathsIncremental Static RegenerationClient sideBuilt-in CSS SupportLayoutsImage OptimizationFont OptimizationStatic File ServingFast RefreshESLintTypeScriptEnvironment VariablesSupported Browsers and FeaturesHandling ScriptsRoutingIntroductionDynamic RoutesImperativelyShallow RoutingAPI RoutesIntroductionDynamic API RoutesRequest HelpersResponse HelpersEdge API RoutesGoing to ProductionDeploymentAuthenticationTestingAccessibilityGuidesBuilding FormsAdvanced FeaturesNext.js CompilerTurbopackPreview ModeDynamic ImportAutomatic Static OptimizationStatic HTML ExportAbsolute Imports and Module Path AliasesUsing MDXAMP SupportIntroductionAdding AMP ComponentsAMP ValidationAMP in Static HTML exportTypeScriptCustomizing Babel ConfigCustomizing PostCSS ConfigCustom ServerCustom `App`Custom `Document`Custom Error Page`src` DirectoryCI Build CachingMulti ZonesMeasuring performanceMiddlewareDebuggingError HandlingSource MapsCodemodsInternationalized RoutingOutput File TracingInstrumentationOpen TelemetrySecurity HeadersReact 18OverviewStreaming SSRReact Server ComponentsSwitchable RuntimeUpgrade GuideMigrating to Next.jsIncrementally Adopting Next.jsMigrating from GatsbyMigrating from Create React AppMigrating from React RouterFAQ

API Reference

CLICreate Next Appnext/routernext/linknext/imagenext/scriptnext/headnext/ampnext/servernext/fontnext/legacy/imageEdge RuntimeData FetchinggetInitialPropsgetServerSidePropsgetStaticPathsgetStaticPropsStatic Optimization Indicatornext.config.jsIntroductionEnvironment VariablesBase PathRewritesRedirectsCustom HeadersCustom Page ExtensionsCDN Support with Asset PrefixCustom Image Loader ConfigCustom Webpack ConfigCompressionRuntime ConfigurationDisabling x-powered-byDisabling ETag GenerationDisabling HTTP Keep-AliveSetting a custom build directoryConfiguring the Build IDConfiguring onDemandEntriesIgnoring ESLintIgnoring TypeScript ErrorsexportPathMapTrailing SlashReact Strict ModeURL ImportsBuild indicatorTurbopack-specific options

Incremental Static Regeneration

Examples

Version History

Next.js allows you to create or update static pages after you’ve built your site. Incremental Static Regeneration (ISR) enables you 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.

Note: The experimental-edge runtime is currently not compatible with ISR, although you can leverage stale-while-revalidate by setting the cache-control header manually.

To use ISR, add the revalidate prop to getStaticProps:

function Blog({ posts }) { return ( <ul>{posts.map((post) => ( <li key={post.id}>{post.title}</li> ))}</ul> ) } // This function gets called at build time on server-side. // It may be called again, on a serverless function, if // revalidation is enabled and a new request comes in export async function getStaticProps() { const res = await fetch('https://.../posts') const posts = await res.json() return { props: { posts, }, // Next.js will attempt to re-generate the page: // - When a request comes in // - At most once every 10 seconds revalidate: 10, // In seconds } } // This function gets called at build time on server-side. // It may be called again, on a serverless function, if // the path has not been generated. export async function getStaticPaths() { const res = await fetch('https://.../posts') const posts = await res.json() // Get the paths we want to pre-render based on posts const paths = posts.map((post) => ({ params: { id: post.id }, })) // We'll pre-render only these paths at build time. // { fallback: 'blocking' } will server-render pages // on-demand if the path doesn't exist. return { paths, fallback: 'blocking' } } export default Blog

When a request is made to a page that was pre-rendered at build time, it will initially show the cached page.

  • Any requests to the page after the initial request and before 10 seconds are also cached and instantaneous.
  • After the 10-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 generates successfully, Next.js will invalidate the cache and show the updated page. If the background regeneration fails, the old page would still be unaltered.

When a request is made to a path that hasn’t been generated, Next.js will server-render the page on the first request. Future requests will serve the static file from the cache. ISR on Vercel persists the cache globally and handles rollbacks.

Note: Check if your upstream data provider has caching enabled by default. You might need to disable (e.g. useCdn: false), otherwise a revalidation won't be able to pull fresh data to update the ISR cache. Caching can occur at a CDN (for an endpoint being requested) when it returns the Cache-Control header.

On-Demand Revalidation

If you set a revalidate time of 60, all visitors will see the same generated version of your site for one minute. The only way to invalidate the cache is from someone visiting that page after the minute has passed.

Starting with v12.2.0, Next.js supports On-Demand Incremental Static Regeneration to manually purge the Next.js cache for a specific page. This makes it easier to update your site when:

  • Content from your headless CMS is created or updated
  • Ecommerce metadata changes (price, description, category, reviews, etc.)

Inside getStaticProps, you do not need to specify revalidate to use on-demand revalidation. If revalidate is omitted, Next.js will use the default value of false (no revalidation) and only revalidate the page on-demand when revalidate() is called.

Note: Middleware won't be executed for On-Demand ISR requests. Instead, call revalidate() on the exact path that you want revalidated. For example, if you have pages/blog/[slug].js and a rewrite from /post-1 -> /blog/post-1, you would need to call res.revalidate('/blog/post-1').

Using On-Demand Revalidation

First, create a secret token only known by your Next.js app. This secret will be used to prevent unauthorized access to the revalidation API Route. You can access the route (either manually or with a webhook) with the following URL structure:

https://<your-site.com>/api/revalidate?secret=<token>

Next, add the secret as an Environment Variable to your application. Finally, create the revalidation API Route:

// pages/api/revalidate.js export default async function handler(req, res) { // Check for secret to confirm this is a valid request if (req.query.secret !== process.env.MY_SECRET_TOKEN) { return res.status(401).json({ message: 'Invalid token' }) } try { // this should be the actual path not a rewritten path // e.g. for "/blog/[slug]" this should be "/blog/post-1" await res.revalidate('/path-to-revalidate') return res.json({ revalidated: true }) } catch (err) { // If there was an error, Next.js will continue // to show the last successfully generated page return res.status(500).send('Error revalidating') } }

View our demo to see on-demand revalidation in action and provide feedback.

Testing on-Demand ISR during development

When running locally with next dev, getStaticProps is invoked on every request. To verify your on-demand ISR configuration is correct, you will need to create a production build and start the production server:

$ next build $ next start

Then, you can confirm that static pages have successfully revalidated.

Error handling and revalidation

If there is an error inside getStaticProps when handling background regeneration, or you manually throw an error, the last successfully generated page will continue to show. On the next subsequent request, Next.js will retry calling getStaticProps.

export async function getStaticProps() { // If this request throws an uncaught error, Next.js will // not invalidate the currently shown page and // retry getStaticProps on the next request. const res = await fetch('https://.../posts') const posts = await res.json() if (!res.ok) { // If there is a server error, you might want to // throw an error instead of returning so that the cache is not updated // until the next successful request. throw new Error(`Failed to fetch posts, received status ${res.status}`) } // If the request was successful, return the posts // and revalidate every 10 seconds. return { props: { posts, }, revalidate: 10, } }

Self-hosting ISR

Incremental Static Regeneration (ISR) works on self-hosted Next.js sites out of the box when you use next start.

You can use this approach when deploying to container orchestrators such as Kubernetes or HashiCorp Nomad. By default, generated assets will be stored in-memory on each pod. This means that each pod will have its own copy of the static files. Stale data may be shown until that specific pod is hit by a request.

To ensure consistency across all pods, you can disable in-memory caching. This will inform the Next.js server to only leverage assets generated by ISR in the file system.

You can use a shared network mount in your Kubernetes pods (or similar setup) to reuse the same file-system cache between different containers. By sharing the same mount, the .next folder which contains the next/image cache will also be shared and re-used.

To disable in-memory caching, set isrMemoryCacheSize to 0 in your next.config.js file:

module.exports = { experimental: { // Defaults to 50MB isrMemoryCacheSize: 0, }, }

Note: You might need to consider a race condition between multiple pods trying to update the cache at the same time, depending on how your shared mount is configured.

Related

For more information on what to do next, we recommend the following sections:

Dynamic routing

Learn more about dynamic routing in Next.js with getStaticPaths.getStaticPathsClient side

Was this helpful?

EMAILFEEDBACKEdit this page on GitHub

Data Fetching: Incremental Static Regeneration | Next.js