Next.jsAdvanced

Next.js Rendering Strategies: SSG, SSR, ISR, and Static Export Compared

Next.js supports several fundamentally different ways to render a page — what each one actually means for when HTML is generated, and how to pick correctly for a given route.

DevFieldGuideJuly 9, 2026 (updated July 14, 2026)6 min read
Share:

Next.js's rendering options are often explained as a historical list (the old Pages Router had getStaticProps/getServerSideProps) rather than what actually differs about when the HTML gets generated — which is the detail that actually matters for choosing correctly.

The core question: when does rendering happen?

Every Next.js rendering strategy answers one question differently: does this page's HTML get generated at build time, at request time, or somewhere in between?

SSGBuild time, once, for all visitors
ISRBuild time, then revalidated on a schedule
SSRRequest time, fresh on every visit
Static exportBuild time only — no server exists at all

SSG (Static Site Generation)

The page's HTML is generated once, at build time, and served identically to every visitor until the next deploy.

tsx
export default async function BlogPost({ params }) {
  const post = await getPost(params.slug); // runs at build time
  return <article>{post.content}</article>;
}
 
export async function generateStaticParams() {
  const posts = await getAllPosts();
  return posts.map((post) => ({ slug: post.slug }));
}

Best for: content that doesn't change per-visitor and doesn't need to reflect changes faster than your deploy cadence — blog posts, documentation, marketing pages.

SSR (Server-Side Rendering)

The page's HTML is generated fresh on every single request, on a real server, using data that can be as current as the moment of the request.

tsx
export const dynamic = "force-dynamic";
 
export default async function Dashboard() {
  const data = await getLiveMetrics(); // runs on every request, fresh
  return <MetricsPanel data={data} />;
}

Best for: genuinely per-request or per-user data — a live dashboard, personalized content, anything reading cookies or headers to render differently per visitor. The cost: a real server is required, and every request pays the full render cost.

ISR (Incremental Static Regeneration)

A middle ground — the page is generated at build time like SSG, but Next.js will regenerate it in the background after a specified interval, so it's periodically refreshed without needing a full site rebuild or paying SSR's per-request cost.

tsx
export const revalidate = 3600; // regenerate at most once per hour
 
export default async function ProductPage({ params }) {
  const product = await getProduct(params.id);
  return <ProductDetail product={product} />;
}

Best for: content that changes, but not so often that every visitor needs the absolute latest version — product prices, article view counts, anything where "up to an hour stale" is an acceptable tradeoff for not needing a server-render on every request.

Static export: no server, ever

output: "export" is a stricter mode than plain SSG — it requires every route in the entire app to be resolvable at build time, produces plain HTML/CSS/JS files with zero server runtime, and can be hosted on any static file host (S3, GitHub Pages, any CDN) with no Node.js process running at all.

ts
// next.config.ts
const nextConfig = {
  output: "export",
};

This site itself runs this way — every route, including dynamic ones like /blog/[slug], is pre-rendered into ./out at build time via generateStaticParams, with no server ever running in production. The tradeoff: SSR and ISR are simply unavailable — there's no server to render per-request or revalidate on a schedule, so anything needing genuinely live data has to fetch it client-side after the static page loads instead.

AspectSSG / Static exportSSR
When HTML is generatedOnce, at build timeFresh, on every request
Requires a server in productionNo (static export) / minimal (SSG)Yes, always
Data freshnessAs fresh as the last deploy (or revalidation, with ISR)Always current as of the request
HostingAny static file host or CDNA Node.js server or serverless platform

Choosing correctly

  1. Does the content genuinely need to be different per-request or per-user? If yes, SSR (or client-side fetching from a static page) — nothing else can give you that.
  2. Does it change, but slowly, and staleness of minutes-to-hours is fine? ISR — if your hosting isn't static-export-constrained.
  3. Does it not need to be fresher than your deploy cadence? SSG — the simplest, cheapest, fastest option.
  4. Do you want zero server infrastructure at all? Static export — accepting that anything genuinely live has to be fetched client-side after the page loads, the same tradeoff behind serving frequently-changing data (like live headlines or prices) from a static site without triggering a full rebuild on every update.

On-demand revalidation: a middle ground within ISR

Beyond a time-based revalidate interval, Next.js also supports triggering revalidation explicitly, on demand, when content actually changes — useful for a CMS-backed site that wants near-instant updates without falling back to full SSR:

ts
// A route handler triggered by a CMS webhook when content is published
import { revalidatePath } from "next/cache";
 
export async function POST(request: Request) {
  const { path } = await request.json();
  revalidatePath(path);
  return Response.json({ revalidated: true });
}

This gives ISR's caching benefits (fast, cached responses most of the time) with SSR-like freshness exactly when content actually changes — the page stays cached and fast until a real update happens, at which point it's explicitly invalidated rather than waiting out a fixed time interval.

Common mistakes

Common mistakes
  • Defaulting to SSR for content that doesn't actually need per-request freshness. This adds real infrastructure cost and latency for content that would render identically as SSG or ISR.
  • Assuming ISR works under output: "export". Static export has no server to run the background revalidation — every route behaves like plain SSG (computed once, at build time) regardless of a revalidate value set on it.
  • Fetching genuinely static content client-side with useEffect instead of rendering it server-side or at build time — this adds an unnecessary loading state and network waterfall for data that didn't need to be fetched in the browser at all.
  • Mixing rendering strategies without understanding the tradeoff being made per route — picking SSR "to be safe" everywhere loses the real performance and cost benefits SSG/ISR provide for content that didn't need per-request freshness.

Frequently Asked Questions

DevFieldGuide
DevFieldGuide

Editorial Team

Practical tutorials and developer tools, written and maintained by the DevFieldGuide team.

Enjoyed this article?

Get the next one straight to your inbox, along with the best of what we publish each week.

Related Articles

More in Next.js

View all