Vercel ISR vs Static Generation for SSGs
Incremental Static Regeneration (ISR) and plain static generation solve the same problem — serving fast, pre-rendered pages — but differ on when pages are built. Static generation builds everything up front at deploy time; ISR rebuilds individual pages on demand after a revalidation window expires. The fact that matters most for static site generator users: ISR is a Next.js feature and requires a serverless runtime. Astro static, Eleventy, Hugo, and Jekyll do not have it — they rebuild and purge at the CDN instead. This page sits under Netlify vs Vercel Deployment Strategies and the broader Production-Ready Deployment & CI/CD Workflows.
Prerequisites
- A site deployed to Vercel, or one you are evaluating Vercel for.
- Clarity on your generator: Next.js (server output) can do ISR; Astro static, Eleventy, Hugo, and Jekyll cannot.
- A sense of your content churn — how many pages change, and how often — since that is the only thing that justifies ISR.
- A CMS or data source that can fire a webhook on publish, if you want on-demand revalidation.
How They Differ
Static generation produces deterministic HTML at build time — zero stale content at deploy, no server runtime, but a full rebuild for any change. That is exactly how Hugo, Eleventy, Jekyll, and Astro (in static mode) work. ISR keeps the static-speed edge hit but lets a page regenerate in the background on the first request after its revalidate window expires, so a high-churn site avoids full rebuilds — at the cost of a serverless runtime and some operational complexity.
In Next.js, the revalidation window is set per page:
// app/docs/[slug]/page.js (or getStaticProps in the Pages Router)
export const revalidate = 60; // seconds: serve cached, regenerate in background after 60s
The visitor-facing speed is the same either way for a cache hit — both serve pre-rendered HTML from the edge in roughly 30ms. ISR only changes who pays the build cost and when.
Why Traditional SSGs Don't Do ISR
ISR needs a server to run the regeneration on demand. A pure static export has no such runtime — which is the whole point of a static site generator. So for Hugo, Eleventy, Jekyll, and Astro-static, "freshen this page" means rebuild (via a Git push, a build hook, or a schedule) and let the CDN serve the new output. If you genuinely need per-page on-demand regeneration, you are choosing a server framework — Next.js or an Astro server adapter — not a static SSG.
When the Rebuild Model Wins
For most static sites, rebuild-and-purge is simpler and strictly better. Consider the numbers on a 1,000-page documentation site where each page changes on a roughly weekly cadence:
| Model | Cost per content change | Stale risk | Runtime needed |
|---|---|---|---|
| Static rebuild + purge | one ~60s build | none after purge | no |
ISR (revalidate=60) | one background regen per page | up to 60s window | yes (serverless) |
If your content changes on a deploy cadence, the full rebuild is a non-event — 60 seconds of CI you never watch — and it guarantees zero stale pages the instant the deploy goes live. ISR only pulls ahead when full rebuilds become genuinely expensive: tens of thousands of pages, or content that changes far faster than you can afford to rebuild everything.
On-Demand Freshness Without a Full Rebuild
If you are on Next.js and want to refresh a page immediately rather than waiting for the window, use on-demand revalidation — the supported mechanism (there is no generic "purge URL" REST endpoint to call):
// app router: revalidate a path from a route handler / webhook
import { revalidatePath } from 'next/cache';
export async function POST() {
revalidatePath('/docs/my-updated-page');
return Response.json({ revalidated: true });
}
Wire that to your CMS webhook so publishing content regenerates just the affected paths — the ISR analogue of pointing a Netlify build hook at a CMS, except it regenerates one page instead of rebuilding the whole site.
Pitfalls & Rollback
output: 'export'disables ISR: a static export strips the serverless runtime ISR needs. Use the default server output if you want ISR; useexportonly when you truly want a static site.- Cache headers fighting
revalidate: a customs-maxageinvercel.jsoncan override the framework's revalidation and serve stale content. Align them or let the framework manage caching. - Expecting ISR from a static SSG: Hugo, Eleventy, and Jekyll cannot regenerate single pages on demand. Rebuild-and-purge is the model; do not design around ISR you do not have.
- Silent staleness from failed regeneration: if background regeneration throws or times out, Vercel keeps serving the last good page. Watch function logs and add error handling in data fetching.
- Rollback: static generation rolls back instantly by re-pointing at the previous immutable deploy. ISR rollback is messier — you redeploy and may need to revalidate paths that already cached the bad version, so test ISR changes in a preview deploy first.
Conclusion
Pick static generation for content that changes on a deploy cadence — it is simpler, has no runtime, guarantees zero stale pages at deploy, and is exactly what a static site generator is for. Reach for ISR only when you have many frequently-changing pages and are already on a server framework like Next.js; then drive freshness with on-demand revalidatePath from your CMS webhook rather than full rebuilds. For the platform-level picture of where this sits among Netlify and Vercel's other differences, see Netlify vs Vercel Deployment Strategies.
FAQ
Does ISR work with static exports?
No. ISR needs a serverless runtime to regenerate pages on demand, and a static export has none — that is the whole point of an export. Static site generators rely on build-time generation plus CDN purging instead. Setting Next.js output to export disables ISR entirely.
How do I refresh one page without a full rebuild?
On Next.js, call revalidatePath or revalidateTag from a route handler triggered by your CMS webhook. On a pure SSG there is no per-page regeneration — you rebuild the affected content and let the CDN serve and purge the new output.
What makes ISR serve stale content past its window?
Background regeneration failing. An unhandled error or a function timeout during regeneration means Vercel keeps serving the last good cached page rather than a broken one. Check the function logs and add error handling in the data-fetching code.
Can I mix ISR and static pages in one project?
On Next.js, yes — static generation for known paths and ISR with a revalidate window for the rest, in the same app. A pure static site generator cannot; it would instead use separate build triggers per content type to control freshness.
Is ISR faster than static generation for visitors?
For a cache hit, no meaningful difference — both serve pre-rendered HTML from the edge in tens of milliseconds. ISR only changes who pays the build cost and when: a regeneration request can be slightly slower while the new page is produced in the background.
Related
- Parent: Netlify vs Vercel Deployment Strategies — where the rendering model fits the platform choice.
- Netlify Build Hooks for Content Updates — the rebuild-and-purge analogue for a static site.
- Setting Up Deploy Previews on Netlify for Every Pull Request — validate rendering changes before they ship.
- Production-Ready Deployment & CI/CD Workflows — the full deployment picture.