SSG means every page is pre-rendered at build and served from CDN forever (until the next build). ISR means pages are pre-rendered too, but Vercel re-renders them in the background on a schedule or on demand. For a content site, the decision comes down to four numbers: build time, freshness needs, function cost, and rollback complexity.
Background
SSG (Static Site Generation) writes HTML during next build or astro build. Every URL becomes a file in out/ or dist/. ISR (Incremental Static Regeneration) is Next.js-specific: pages are still pre-rendered, but stale pages trigger a background regeneration on the next request after revalidate seconds. Vercel supports both, but ISR needs a Node serverless function as the renderer.
How to tell
- Your build takes over 5 minutes and you have hundreds of articles — ISR can split the cost across requests instead of bunching it at build.
- You publish 20+ updates a day across a small editorial team — ISR or on-demand revalidation avoids 20 redeploys.
- Your content is fully static (legal pages, docs, archived posts) — SSG is simpler and cheaper.
- You hit Vercel’s build time limits (45 minutes on Hobby, longer on Pro) — that is the loudest ISR signal.
Quick verdict
Under 500 articles, infrequent edits, fast build: SSG wins. Over 2,000 articles or daily updates: ISR with on-demand revalidation wins. In between, either works — pick by team workflow, not benchmarks.
When SSG is the right answer
Five real signals that SSG is enough:
- Build takes under 3 minutes — no pain to redeploy for an edit.
- Editors are comfortable with git, or a CMS already triggers a redeploy on save.
- You want the most boring possible production: CDN serves files, no function invocations, no surprises.
- Rollback is “promote the previous deployment” — instant, atomic, no cache eviction needed.
- Your hosting bill should be roughly the cost of a CDN, period.
Astro defaults to SSG with output: 'static'. Next.js defaults to SSG for any route with generateStaticParams and no dynamic APIs.
When ISR pays for itself
Three concrete cases:
- Build time is the bottleneck. 5,000+ articles, build takes 20 minutes, every typo fix is a 20-minute wait. ISR builds only the most popular slugs and lazily regenerates the rest:
// app/articles/[slug]/page.tsx
export const revalidate = 3600; // ISR: regenerate at most every hour
export async function generateStaticParams() {
// Only pre-render the top 200; rest are lazy
return (await getTopArticles(200)).map(a => ({ slug: a.slug }));
}
- On-demand revalidation from a CMS webhook. Editor hits Publish in Sanity / Contentful, the webhook calls
/api/revalidate, the one affected URL regenerates in seconds. No full redeploy:
// app/api/revalidate/route.ts
import { revalidatePath } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';
export async function POST(req: NextRequest) {
const secret = req.nextUrl.searchParams.get('secret');
if (secret !== process.env.REVALIDATE_SECRET) {
return NextResponse.json({ ok: false }, { status: 401 });
}
const { slug } = await req.json();
revalidatePath(`/articles/${slug}/`);
return NextResponse.json({ ok: true, revalidated: slug });
}
- Scheduled revalidation for changing fragments. Article body is fixed, but a “related articles” rail needs refreshing weekly. Set
revalidate = 604800and the page rebuilds itself.
Rollback differs
- SSG rollback is one click — Vercel promotes the previous build, atomic across all pages.
- ISR rollback is trickier — the previous deployment may still hold stale regenerated copies in the function cache. Use
revalidatePathorrevalidateTagafter promoting, or wait out the TTL.
Common mistakes
- Setting
revalidate = 60on every page “to be safe” — you have just turned every request after the first cold one into a function invocation. Bill goes up, CDN hit rate goes down. - Using ISR but no on-demand hook — editors still wait for the revalidate window to see their changes live.
- Forgetting that ISR needs Node serverless functions deployed, not just static files — affects cost model and which Vercel plan you need.
- Mixing SSG and ISR in the same app and being confused why a page shows old content — check
export const revalidatein the segment. - Treating Astro’s
output: 'hybrid'as “Astro ISR” — it is closer to SSR per route. Astro does not have true ISR in 2026; it has on-demand regeneration via the Vercel adapter.
FAQ
- Is ISR worse for SEO than SSG?: No. Both serve pre-rendered HTML to crawlers. ISR’s first regenerate after a redeploy may be slightly slower; subsequent hits are CDN-fast.
- Can I use ISR with Astro?: Sort of. Astro has on-demand rendering with the Vercel adapter, but not “stale-while-revalidate” timing semantics like Next.js. Astro content sites are usually fine on SSG.
- What about Vercel’s “Data Cache”?: That is per-fetch caching, orthogonal to ISR. You can combine them: ISR caches the rendered page; Data Cache caches individual
fetch()calls inside it. - What happens if a regenerate fails?: The stale page keeps serving. You will see the error in Vercel logs, but users see the last-known-good HTML — that is the whole point.
- Is ISR the same as
revalidateOnInterval?: Same idea, different framework. Astro and SvelteKit on Vercel use different terms, but the cache primitive is the same.