Skip to content

RFC: Incremental Static Regeneration #11552

timneutkens announced in RFC
RFC: Incremental Static Regeneration #11552
Apr 1, 2020 · 82 comments · 364 replies

Update: This has been released. See the docs for more information. The RFC will remain for historical context.


Fully automatic re-rendering of statically exported pages without a full rebuild.

With regards to static site generators this feature has been referred to in multiple ways, most commonly "Incremental builds" or "Incremental rebuilds".

This RFC exclusively discusses API additions. All new functionality is completely backwards compatible and can be incrementally adopted. This RFC introduces no deprecations.


Next.js recently introduced support for next-gen Static Generation (SSG) in v9.3.

Generating static pages in Next.js using getStaticProps and getStaticPaths provides numerous upsides:

  • Faster Websites: Generated files can be served from a global CDN close to your users
  • Reduced Costs: Request are not rendered on-demand for every user

However static generation as it exists today has one downside that makes it hard to adopt for larger websites or applications:

Every time something changes in the database a full rebuild is required in order to see the change in one single page.

An example to illustrate this is when you make a change to a blogpost in a headless CMS, you could be only updating the title of one blog item. After you make the change the application would require a full rebuild of all pages, just to make that one change visible.

In order to make static sites scale we have to regenerate pages without needing a full build of the application.

What if we could generate a new version of the page on-demand when a new request comes in, but without having the user wait for the re-rendering?

Effectively re-rendering the page in the background while the previous version of the page keeps being served.

The background re-rendering could be triggered based on a timeout, similar to the way that Cache-Control's maxage works, when the timeout is exceeded a background re-render is triggered when a request comes in.

This would look something like:

  • The page defines what timeout is reasonable, this could be as low as 1 second
  • When a new request comes in the statically generated page is served
  • When a new request comes in and the defined timeout is exceeded:
    • The statically generated page is served
    • Next.js generates a new version of the page in the background and updates the static file for future requests
  • When a new request comes in the updated static file is served

This model is pretty ideal for static generation:

  • Works in the background, users always get a static response
  • Pages get statically re-generated, including all changes from the CMS
  • It's fully automatic, no need to trigger a full rebuild

This allows for true incremental rendering of static pages in Next.js.

After this RFC for incremental static generation is implemented we can extend it to do force revalidation, which would be useful for CMS providers that want to get the content updated as quickly as possible.


Next.js 9.3 introduced getStaticProps, in getStaticProps you'll be able to return a revalidate property in order to opt-in to automatically generating in the background when a request comes in:

// pages/blog/[slug].js
export async function getStaticProps({ params }) {
  const post = await getBlogPostBySlug(params.slug);
  return {
    // Set the timeout for generating to 1 second
    // This timeout could be longer depending on how often data changes
    revalidate: 1,
    props: {

Keep in mind that the timeout defined is a timeout for when an incoming request will re-render in the background. Meaning that the first request after the timeout period will serve the previously rendered page and then the page is regenerated in the background.

When you opt-in to revalidate you get:

  • Fully static rendering
  • Automatic re-generation in the background when a request comes in

Co-authored with @rauchg @Timer
Special thanks to @juancampa @dav-is


364 replies

So excited for the future!

0 replies

You would still need a full rebuild if you change something shared with all pages eg header, correct?

10 replies

Only if your code changes. In cases of data it can just be re-rendered.


I was thinking about this scenario in the past as well. Say we have a home page, and a product page, and we put different revalidate timings onto them, and both are sharing a common header and footer. Depending on the page routing capabilities, those 2 could become out of sync with each other.


Yes definitely but in general this is already the case when building CDN backed applications. We're going to extend these capabilities to do a "force regeneration" through API routes after this has landed though. There's a bunch of ways to solve this and I wanted to keep the initial implementation simple.

This looks awesome, a great proposal 🚀

As you stated on the upsides:

Reduced Costs: No server-resources are needed to render every request on-demand

  1. If a specific page is requested several times throughout the day, doesn't this mean a lot of API/DB calls to check if the content has changed?
  2. Will it work for getStaticPaths? (i.e. adding or deleting a blogpost from a CMS)
12 replies
  1. We run at most one invalidation concurrently, and the call itself is usually super cheap. Consider that most headless CMS providers put your content in a CDN already optimized for high read throughput, so requests are incredibly cheap.

    Even if you were querying an unoptimized slow WordPress instance backed by a tiny MySQL instance, the load would be minimal and if necessary you could cache.

  2. Yes. This is why we introduced a fallback option. We want the requests to always be fast. If a data point is added later in the life of your site, by default we will render a skeleton directly from the edge.


To expand on @rauchg:

This is why the revalidation period is configurable! We expect this to vary a lot by use-case.
Also, per the RFC, if the page isn’t being visited by users, revalidation will be temporarily paused for this exact reason (reducing compute).

We'll be exploring on-demand (triggered via API route) revalidation instead of interval-based in the future.

Great question!


Thanks, @rauchg and @Timer! On-demand revalidation it's a great idea.

Great to see another RFC in this area. A few specific points of feedback:

1: It took me a while to realize that this would happen on the server (or a serverless platform like Now) at runtime. The word static is commonly associated with a build-time process, producing something that can be uploaded to a "dumb" CDN.

I sort of realize now that you're talking about the end user experience – they would always get a static HTML – but this RFC basically proposes a behavior that's similar to SSR + nginx microcache (please correct me if I'm wrong) and that's not commonly referred to as SSG.

2: With these micro-caching strategies, it's often problematic to set the "right" timeout. In fact, there often isn't any one value. That's why most CMS's don't send aggressive cache-control headers and prefer to feel "slow" rather than outdated. I guess it's also why the example uses 1 second 😄.

You could argue that if you know your site, you can set this number sensibly but in my experience, it's always a tough choice.

3: In the RFC, it might be worth pointing out what this background re-rendering means for the backend uptime guarantees. With SSG, I can turn the headless CMS off after I've generated the site; here, I don't.

I assume that if the response from the backend is an error, the previously rendered HTML is still returned. This could also lead to situations where /post/my-blog-post already has the new title but /category/my-category/page/2 still displays the old value (backend was unreliable; I used a different timeout for that page, etc.)

27 replies
  1. It's incremental static generation because the goal is to route directly from the edge to a static file, no server in between. This maximizes availability and performance.

  2. Sending cache-control is a bad idea primarily because you'd cache on the end user's device, and users are unlikely to consume the content more than once, so it's a pointless optimization. Plus, at that point invalidation is impossible until time passes.

    I disagree that slow or unavailable is better than slightly behind. This feature exists primarily for the category of pages where that is the absolute correct tradeoff (in other words, this is a good fit for eventual consistency). Any page where the amazon 100ms rule applies: landing pages, marketing content, blog posts, e-commerce, travel, etc.

  3. You absolutely can turn off the backend and CMS. You won't get forward updates, but all the HTML that you produced with getStaticProps and getStaticPages at build time will stay there.


Adding my 2¢:

Regarding point (1), this is different than SSR + nginx microcache and opens up a wealth of possibilities in the future.

  • Because this is SSG and not SSR, the first user-request will not be blocking and cannot 500 if your upstream CMS/etc is down. It's served immediately from the file system (or CDN edge when configured).
  • Since this is a framework concern, we can declaratively express dependences between groups of pages that need to be invalidated. We have intent to explore returning a set of keys from getStaticProps that would allow you to express a dependency graph (across pages) for an all-or-nothing incremental update.

Regarding point (2):

Revalidation on an interval is just the beginning for this feature! Using the same keys mentioned above, we could allow you to trigger revalidations on-demand using an API endpoint.
This would change the model to be event-driven instead of interval-based.

Regarding point (3):

With SSG, I can turn the headless CMS off after I've generated the site; here, I don't.

You can definitely turn off the upstream CMS, database, or API! This is SSG—your site will remain online and would return the latest incrementally generated content (or build-time content if the outage occurred between build and deploy).

Is there a way we can make this more clear in the RFC? Can you explain what made you think this may act like or be SSR?


Using the same keys mentioned above, we could allow you to trigger revalidations on-demand using an API endpoint.
This would change the model to be event-driven instead of interval-based.

I'm highly anticipating this, as I have a lot of dynamic/incremental(?) pages and I consider it the most efficient approach to be able to simply trigger revalidation from my api when it actually becomes necessary.

Some kind of dependency graph with a way to exactly determine which pages need to revalidate based on a shared reference for some data they rely on could also be a great feature for bigger pages. I could think of even more great usecases, like listening on websockets for changes, but some of these concerns could probably just split into a separate applications that takes care of this as long as nextjs just offers some api to trigger a revalidation.

First up, I really like this RFC. You folk already had me interested with getStaticProps and getStaticPaths, but this is next-level exciting! 🎉

My initial response:

  1. How are revalidated pages stored? Like technically? At first I thought this was just a simple memory cache. The mention of a CDN now leads me to believe you are actually saving static files, in exactly the same way as when I'd run next build? That'd be really cool!

  2. Would this work well for a situation where you have thousands or tens of thousands (public!) variations of a page? For example, could I simply not define getStaticPaths and let the built happen on-demand once deployed to a server? Any immediate downsides to that approach? I expect a small delay for the first visitor, but besides that?

  3. This is not a question, merely a small suggestion... It might be nice to explain how this differs from Serverless Pre-Rendering. Both ISG and SPR have their unique use cases, but they're hard to differentiate if you're not already really familiar with both concepts.

14 replies

From my observations, yes, this creates actual html + json files with the pages/path segments tree like you have it defined in you pages folder under .next/server/static/CURRENTBUILDID/pages/.
The JSON file contains the pageProps for each page.


@janhoogeveen great point on 3) – we consider this the spiritual successor of SPR. It addresses a key problem with that approach: that the initial "cache" is not seeded, so there's a "cold hit" for most of your pages. We realized that's unacceptable for all the pages that could easily be produced at build time (like marketing pages, most of your blog pages, your popular e-commerce items, etc)


  1. Revalidation is performing an incremental rebuild (akin to next build) and storing the result on disk. If you were to reboot your Next.js server after a few hours, the first request would be the last incremental rebuild! Similarly, user requests are always served from disk (or memory, with the disk being watched for changes)!

  2. iSSG satisfies this use case perfectly! If you have 10,000+ product pages but only want to render your most popular 100 at build time, you can opt-into the fallback behavior which allows static generation to be deferred until the first request.
    When a user request comes in for a page not generated at build-time, they'll be served a static skeleton (the request will not block). You can then show a loading state on the client-side while the incremental build is happening specific for that page!

Great proposal, thanks for this!

I'd love to see an API for event-driven changes. @Timer already mentioned it's on your plans, so I'll just share my current use case and why it would be helpful.

Currently, I'm using Next.js with a Firebase backend to build a collaborative platform for learning where users can edit any page (similar to how Wikipedia works). This means a page can change multiple times a day. This RFC would allow me to use getStaticProps and have faster loading times. However, it wouldn't allow me to save much money on Firebase read requests because I don't know how often that page will be updated. So, I'd have to set revalidate to a low number.

However, I could save lots of money if we'd have an event-driven API because I could create a Firebase Cloud Function for listening to post changes, for example, and send a request to update that post's page only.

Anyway, I'm glad to see the direction you're going. I've been working with Next.js for less than a year but it has been a great experience so far. Thanks for your hard work!

2 replies

You may find this Firebase talk interesting -
It covers content-change rendering with Firebase.


An event-driven API would be extremely useful—or additional option on the current build script. We are looking more into static page generation but could potentially have 1000s of pages in various languages. Being able to programmatically "push" regeneration of an individual page when its content is changed would be ideal (e.g., fixing a typo in the CMS).

Or, perhaps, if a whole subdirectory of a site had a common element change, it would be nice to tell a collection of pages to regenerate—maybe through a regex/glob/list of path(s).

I have this feature today. We run nextjs in a docker container in Fargate. We have a CDN that fronts all of that. Each request hits our CDN, then our origin (Nextjs). If the page exists in the CDN, the origin doesn't get hit, bit it doesn't then nextjs serves the response.

When "our database updates", we just proc a cdn cache invalidation to that changed route, and depended routes for that matter.

The only thing I see this new pattern solve, is being able to de-bounce failed responses, with previous successful responses.

We serve close to 300k distinct pages out of nextjs, if we flick on SSG - would we need disk space to house all of those html docs?

2 replies

Although this may vary heavily, for reference my pages use Material UI and some other libraries(i.e there are not the smallest), and the generated revaliated fallback pages have a size of ~100 kb each. Add to that the size of the accompanying json file with the generated pageProps, in my case these are around 10kb each as they contain a lot of product data.
Nextjs stores only the latest copy, so with 300k of these pages I would probably be at around 33 Gigabytes. In my case Im rendering per locale, so for two locales I offer on the page that would be 66 GB, just in case i18n is a concern.


When "our database updates", we just proc a cdn cache invalidation to that changed route, and depended routes for that matter.

This approach work on individual pages, but what about some listing pages and search results?

If someone changes the title of the article/product, you purge only this individual URL, but everywhere else CDN continues to returns the old one.

Great proposal!

I have a question. In our e-commerce we are using SSR returning different content depending on the delivery country (stored on a cookie), but the page route can be the same (bots always see the default delivery country because they don't change the country).

Is there any plan to support this? Or the only way is to add an extra slug with the delivery country...?

7 replies

In general I'd recommend separating language routes as then they can be indexed per language and cached on a CDN.


Sorry for the tangent @timneutkens, but is there any SSG-friendly i18n example available? This solution does seem to only work with SSR. Any high level direction would work too. Thank you!


@vgrafe We published an i18n lib SSG-friendly with next.js (it also works for fully static site):

The solution has an extra build step with a CLI, as a temporal workaround meanwhile there is not a better solution...

How would this work if the site assets are built with a CDN prefix; in addition to having multiple copies of the same container/build running in a ECS cluster, around 200 of them at the same time?

1 reply

You'll want to read this thread #11552 (reply in thread)

Awesome proposal and I love how fast you are moving forward with static generation options. Combined with the fallback option I'm starting to consider using it.

We're running, an Swiss German online magazine, on next.js starting with v2 and running v9.3.4 right now. Currently we're still 100% server-side rendering—using apollo in getInitialProps. I'd like to move to a more hybrid approach and start useing the static features of next.

While a bit off topic, here is what currently is still blocking me:

  • being able to return proper 404s with fallback: true
  • flexible segmenting into two or more user groups with different caches
    • public / no cookie, cache interval 5 minutes, html with pay notes
    • signed in, cache interval 1 minute, html without pay notes
    • editors, live mode—no cache

I considered abusing preview mode for the «signed in» segment but that felt wrong. Maybe preview mode could be made more flexible—allowing a custom function to determine whether to live render or not. For us live rendering for signed in users would be an option because we've already build an html partial caching solution.

The non-plus-ultra solution for us, and maybe other hybrid users, would be to have a custom segmenting function that determines which cache and caching strategy should be used for a request. Maybe this function could also solve the 404 case: use live mode if not part of the current static path list.

5 replies

This is the bit I can't get my head around, when using fallback:true a status 200 is returned every time. 301s, 302s and 404s all not possible, so not great for search engines unless I've missed something.


@tpreusse Did you already found a solution for the 404 issue?


bump, any update on this?
Perhaps we should raise this as a separate issue, given that this feature has already been implemented?

I agree, not being able to return a non-200 http header is problematic.
I see how it's technically impossible to do with fallback: true. But with fallback: "blocking", it should be possible to do.

One of the big feature of a SSG website is the ability to put it on a CDN: incremental build for me is like a partial CDN purge and about it for my static contents I'm using Fastly and its Surrogate Keys feature: you can tag a content with one or many tags as you want and then purge it by tag and not a full purge of the cached contents.

In this direction I think rebuild in background only the pages tagged by a key could be the right approach (calling an API with one or more keys).

2 replies

Smart and yet simple way to go about relationship between pages. It's also very much simpler to understand from a human point-of-view about how cache invalidation would work.

@Timer Are you considering such approach? I read above you were already working/designing cache invalidation by API, what do you think of this implementation?


you can tag a content with one or many tags as you want and then purge it by tag

Yes, but Fastly have a 1K API calls per hour limit - for some busy sites like e-commerce or classifieds, users can hit these limits very fast - we always have an option to put all of them on any kind of Queue service for the subsequent execution, but this is definitely not a solution when you need guaranteed consistency.

If you have a cluster of many NextJS instances running at the same time, and node1 receives a request and regenerates a static page, wouldn't node2 (not hit by any request currently) be out of sync?
Given enough time, all nodes might start to become out of sync, and have different revalidation timestamps no?

I guess it could be mitigated by having a caching layer on top, and ensuring that if node1 revalidates, then the cache will not hit node2 before the new node1 static content expires.
But will it always be the case in practice? Will this solution work if we just put a simple round-robin load-balancer on top of the cluster?
In such case 2 nodes might serve 2 different pages, randomly?

(just thinking out loud)


  • Why not using the term "TTL" instead of timeout, for a static page? caching terminology seems relevant here
  • Also, all this makes me think of the "stale-while-revalidate"/SWR (or "cache-and-network" / Apollo), pattern looks very similar
2 replies

@slorber this is happening for me. I have pm2 with multiple instances and page randomly starts showing 2 versions. Right now to fix this i have to redeploy the app.

Do you have any solution?


@nimitwalia89 unfortunately not, I don't even have a NextJS with iSSG in production, it's just something that I thought could happen. If you have the answer to this problem, I'm curious.

This is a good start imho to make static sites more accessible. However it would be ideal to be able to send some kind of trigger to the server with a flag or something in those lines that a page needs to be rebuild.

isn't it a waste of resources if you'd work with only the timeout option? (not sure how much it uses)

0 replies

Is this available with v9.3? Or is it at the proposal stage?

1 reply

It's still a proposal

Thank you @timneutkens ,
I tested and its a great feature. But can we do something with query parameter in getStaticProps

if in URL query parameter has '?refresh=1'
const refresh = 1; return { unstable_revalidate: refresh, props: { item } }

and when will be the stable version of it.

6 replies

One of the reasons that we didn't add this into the spec initially is that it would need vendor lock-in in order to work on a hosting provider, eg we can make this work with next start and on but it's increasingly hard to get right when working with other CDN solutions (providing querystring values that is).

Overall the ideal solution is reading the querystring values client-side.


Yes, But actually I am looking to create a CMS where user can publish their own content from SSR to SSG. So my idea is when the parameter will pass in URL then the page will update with updated data just like cache refresh. It is working nice in background but I am looking for this solution so that user will know exactly what he is publishing


Oh I see, we're going to add additional features to force regenerating pages (as discussed in above threads) after this lands. What you're looking for in particular is preview mode which is currently available:

Hey everyone! There's been a lot of discussion here about programmatically purging routes that have been generated with ISR. We're happy to share we're actively working on this now 😄 We've spent the time since this feature launched evaluating options and have come up with a solution we think you'll love.

Stay tuned! 🚀

68 replies

I love to see this feature as I am also looking for the same.


yay! this is exciting.


This will change everything 🤩

I am using ISR but adding new blogs, editing doesn't seem to be working on the production.

// /blogs/[slug].js

export async function getStaticProps({ params }) {
  const res = await api.get(`/api/v1/blogs/${params.slug}`);
  const blog =;
  return { props: { blog }, revalidate: 60 };
export async function getStaticPaths() {
  const res = await api.get("/api/v1/blogs");
  const blogs =;
  const paths = => ({
    params: { slug: item.slug },
  return { paths, fallback: false };
1 reply

"fallback:false" means that only pregenerated pages are available. Try fallback:true or fallback:'blocking' and check docs again

Is it possible to specify the location of the generated pages? At the moment SSG can be manually uploaded to S3 on build time, but pages generated from ISR are stored on the server, and it is becoming unmanageable as we're generating 70Gb of cached pages per day.

1 reply

Is it even possible to cache page generated with ISR when not hosting on vercel or it should always be served from .next/server ?

I'm using revalidate on my blogging website, but I've run into a huge caveat. The problem is that next/link client-side transitions do not trigger the revalidation. They always get the pre-built / pre-fetched json props. They never trigger the getStaticProps again. Even worse, the prefetched json is cached on client, so even if you transition to a page that has been revalidated by some other request, you still get stale client-cached pre-fetched data. A user might get stuck on a stale version of your website page for ever.

Can we have a way to trigger page revalidation with client-side transitions using next/link ?

I had to update my whole website to use regular <a> tags instead of client-side transitions, to make sure pages will be revalidated.

Anyone else facing this?

7 replies

Here fighting with the very same issue. I'll stay listening for some solution.


It's a bit of a hacky approach, but the way I do it is trigger GET requests to all pages that need to be updated after data is updated.


It's a bit of a hacky approach, but the way I do it is trigger GET requests to all pages that need to be updated after data is updated.

I've been thinking about doing something like that:

  • Use next/link to do client side transitions.
  • Send fetch GET request (on background) on every URL change to make sure it will trigger page revalidation
  • Full reload of website using setInterval in order to get fresh data

That feels really hacky though. The ideal would be for the next/link transitions to be able to trigger page revalidations so the client can get fresh data.

Is this implemented?

3 replies

Yes. First sentence of the document:

Update: This has been released. See the docs for more information. The RFC will remain for historical context.


I'm taking about on demand ISR.


You're commenting on the RFC for incremental static generation. Not the comment where we shared we're working on manually revalidating: #11552 (comment)

You can follow that comment as we'll post back when it's implemented.

Hi team,

Can we configure the max cache for ISR? Currently, we have some 404 on ISR page. The number of 404 is very small compare to the request (2x vs 11k). I'm in doubt that because the cache is LRU and size is not enough. We need to increase the max cache for that. How can I do that? Or do we have any plan to support that soon?


0 replies

@timneutkens As I understood the way Next ISR do not have anything similar to Gatsby's incremental builds which only build pages which were changed on the 2nd run, what Next have is persistent cache which users can roleback. (no sharing of cache between deploys, so second build still build the unchanged pages). Am I right here?

0 replies

Hello, quick question - is it possible to trigger manually revalidation by API?

My scenario:

  1. Site has static content
  2. Admin can enable special feature on site (buy button / price / whatever)
  3. Admin updates this value few times per week
  4. I want to trigger revalidation after admin changes as my site is just static content with few variants which i want to switch and send to user as fast as possible (set revalidation to 1 min can solve it but it's still 1 minute and 24*60 calls to my backend daily)
1 reply

It's not possible at the moment, see #11552 (comment)


What is supposed to happen when client send a 'Cache-Control: no-cache' header or '_vercel_no_cache=1' request parameter?

Does-it force cache regeneration?

0 replies

@leerob @timneutkens Is there perhaps anything us mortals can do to help build this feature? It's an open source project after all, so it's only fair that we chip in ;). I have never dived into the Next.js code before, but I assume creating a webhook to rebuild a specific page should not be rocket science. Even though as far as I know the Next.js server doesn't offer any API endpoints specifically to instruct the server to perform any type of "administrative" tasks, like rebuilding pages on command (correct me if I'm wrong). I suppose the on-demand image optimization endpoint comes closest.

Not making any promises that I do have time to get into this, but it does sound doable, and I REALLY want this feature. Plus it sounds like fun to dive into the code. I'm curious to see what kind of black magic you guys have utilized to make everything fall into place like this.

EDIT: I'm talking about the manual triggering of page rebuilds: #11552 (comment)

0 replies

I believe we really need this feature asap! Can’t really stress out how important I believe this is for future development.
Hope we can see something soon 🙏

0 replies

im currently working on project and page have

// in getStaticPaths
 if (paths.length > 0) {
    return { paths, fallback: true };
  } else {
    return { paths: [], fallback: 'blocking' };

// in getStaticProps
if (data) {
    return {
      props: { data },
      revalidate: 1,
  } else {
    return {
      notFound: true,

and data is not in database anymore but i keep having it on the page even with refreshes changing routes then coming back to same page to find data still cached

am i doing something wrong here ? and would love to be able to manually purge / revalidate

1 reply

you cant manually purge yet but you can go to the page and refresh it twice to cause it check validation again

After this RFC for incremental static generation is implemented we can extend it to do force revalidation

@timneutkens May I know the status of force revalidation

  • expected date
  • will nextjs implement this feature or not?
0 replies

I have a strong feeling that this is going to be released this week given Lee's tweet and the interactions on Twitter 😄

2 replies

It's not looking like that, let's see


I’m reading it the same as @madx

I'm incredibly excited to share that Next.js 12.1 was just released, which includes on-demand Incremental Static Regeneration! We know many of you have been looking forward to this for a while, including myself, and I'm so happy it is here.

16 replies

Yayyyy thank you @leerob and team!! 🚀


Omg!!! @leerob, thank you and your amazing team!!! Unbelievable!


I have been on a loop of pages looking for a solution, to my surpise the solution has been announced just now 😆

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet