Using Incremental Static Regeneration in Next.js to Update Jamstack Pages Without Full Rebuilds
Learn how ISR lets you serve cached pages while updating them in the background, with a concrete Next.js example, setup steps, and limits to watch.
17 Dec 2025, 11:43 UTC

What ISR gives you in a Jamstack workflow
Incremental Static Regeneration (ISR) lets a Jamstack site serve a pre‑generated HTML page while quietly updating that page in the background. The first visitor gets a static file; after a configurable time interval, Next.js regenerates the page and swaps the new version into the cache without a full site redeploy. This keeps build times short and reduces the need for a traditional server while still delivering fresh content.
Worked example: a blog page with ISR
The following code shows a minimal dynamic route for a blog post that uses ISR. It assumes a headless CMS that returns JSON for a given post ID.
// pages/posts/[id].js
import { notFound } from 'next/navigation'
export async function getStaticProps({ params }) {
const res = await fetch(`https://my-cms.example.com/api/posts/${params.id}`)
if (!res.ok) {
return { notFound: true }
}
const post = await res.json()
return {
props: { post },
revalidate: 60, // seconds – regenerate at most once per minute
}
}
export async function getStaticPaths() {
// Allow any post ID to be generated on demand
return {
paths: [],
fallback: 'blocking', // enables ISR for dynamic routes
}
}
export default function Post({ post }) {
return (
{post.title}
)
}
Key points:
getStaticPropsreturns arevalidatevalue (in seconds). After the first request, Next.js will serve the cached page and, once the interval passes, regenerate it in the background.getStaticPathsusesfallback: 'blocking'so that any unknownidtriggers a server‑side render on the first request, after which ISR takes over.- The page remains fully static for visitors; no Node.js server is required to serve the cached HTML, only to perform the occasional background regeneration.
How ISR works under the hood
When a request arrives for /posts/abc123:
- Next.js checks if a cached HTML file exists for that route.
- If it exists and is younger than the
revalidateinterval, the cached file is returned immediately. - If the cached file is older than the interval, Next.js returns the stale HTML while spawning a background render to produce a fresh version.
- The background render updates the cache; subsequent requests see the new HTML.
This means the site never blocks a visitor while waiting for a rebuild, yet the content stays reasonably up‑to‑date.
Verification steps
Local development
Run the development server:
# Run in your project root next dev
- Request the page (e.g.,
http://localhost:3000/posts/abc123) and note the response headerx-nextjs-revalidate– it should be1indicating a background regeneration is scheduled.- Wait longer than the
revalidatevalue (e.g., >60 seconds).- Request the same URL again. The header will again show
1(another background regen) while the body reflects any changes made in the CMS.No full rebuild appears in the terminal; you’ll see only the initial render log.
Production on Vercel
Deploy the same code to Vercel. In the Vercel Dashboard:
- Open the Analytics tab for the deployment.
- Look for cache misses after the revalidation interval – a miss indicates a new static file was generated.
- Check the Builds section: only the first request triggers a render; subsequent requests within the interval show “cached” and no new build step.
Self‑hosted Node server
If you run
next starton a VPS or Docker container, inspect the server logs. The first request logs “Generating static page …”. Later requests within the interval log “Serving from cache”. After the interval, you’ll see a background regeneration line without blocking the response.Limits and platform requirements
- Node‑only environments: ISR needs a Node.js server to run the background regeneration. Pure static hosts such as GitHub Pages, Netlify’s static site mode, or Cloudflare Pages without edge functions cannot run ISR.
- Revalidation frequency: Setting
revalidatetoo low (e.g., 1 second) can cause excessive regenerations, increasing load on your origin CMS or API and raising costs. - Data suitability: ISR works for data that can be safely cached and shared across users. Pages requiring authentication, per‑user personalization, or real‑time data should use
getServerSidePropsor client‑side fetching instead. - Fallback configuration: For dynamic routes, omitting
fallback: 'blocking'(ortrue) will cause Next.js to return a 404 for unknown paths, disabling ISR.
Common mistakes to avoid
- Using
revalidate: 0– this disables ISR and forces a full rebuild on every request. - Assuming ISR works on Vercel’s Edge Functions without a Node runtime; you must enable the Node.js compatibility flag.
- Fetching private data (e.g., cookies, headers) inside
getStaticProps; that data will be baked into the cached HTML and served to all visitors. - Neglecting to purge or invalidate the CMS cache when content changes, leading to stale data being regenerated.
Practical way to check the result
The most reliable indicator is the response header x-nextjs-revalidate:
1– a background regeneration is in progress or just completed.0– the page is being served from cache and no regeneration is scheduled (either because the interval hasn’t elapsed or ISR is disabled).
By watching this header change over time, you confirm that ISR is active without needing to inspect build logs or deployment metrics.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.