Static Site Generation (SSG)

Master Static Site Generation in Next.js — pre-building pages at deploy time for maximum performance, CDN delivery, and zero server costs.

Last reviewed: January 2025

·Next.js 13Next.js 14Next.js 15
✅
Quick Understanding: SSG pre-builds your pages as static HTML at deploy time. The result is served instantly from a CDN — no server processing, no database queries per request, just files. In the App Router, routes are static by default unless you opt into dynamic rendering.

🔍 What Is It?

Static Site Generation (SSG) pre-renders pages to HTML at build time (next build). The HTML files are:

  • →Stored and served from a CDN
  • →Identical for every user (no personalisation)
  • →Blazing fast — no server processing per request
  • →Infinitely scalable — CDN handles any traffic spike

In the App Router, SSG is the default. A route is static unless it:

  • →Reads cookies() or headers()
  • →Uses searchParams
  • →Calls fetch with cache: 'no-store'
  • →Exports dynamic = 'force-dynamic'

For dynamic routes (/blog/[slug]), use generateStaticParams to tell Next.js which slugs to pre-build.

🎯 Why Do We Need It?

SSG is the fastest possible way to serve web content:

  • →No server cost per request — CDN serves a file, no compute needed
  • →Sub-50ms response times — CDN edge nodes are geographically close to users
  • →Infinite scalability — CDN absorbs traffic spikes without autoscaling
  • →No database at request time — database is only queried at build time
  • →Perfect SEO — full HTML available for crawlers immediately

For content that doesn't change per user (marketing pages, blog posts, docs, product listings), SSG is almost always the right choice.

🏗️ What Happens in Real Projects?

SSG in a real e-commerce platform:

  • →/ — homepage with featured products (SSG, rebuilt on deploy)
  • →/products — product listing (SSG + ISR, revalidated hourly)
  • →/products/[slug] — each product page (SSG with generateStaticParams)
  • →/blog — blog listing (SSG, rebuilt on new post)
  • →/blog/[slug] — each blog post (SSG, rebuilt on edit)
  • →/about, /pricing, /contact — pure static HTML

A large e-commerce site might pre-build 500,000 product pages. Next.js handles this with parallel build workers.

⚙️ How It Works

SSG build pipeline:

  1. next build starts
  2. Next.js identifies static routes (no dynamic dependencies)
  3. For dynamic routes, it calls generateStaticParams to get all slugs
  4. It renders each route as an async Server Component, fetching data
  5. Outputs HTML files + RSC payloads for each route
  6. At runtime, CDN serves the pre-built files instantly

generateStaticParams:

export async function generateStaticParams() {
  const products = await db.product.findMany({ select: { slug: true } });
  return products.map((p) => ({ slug: p.slug }));
}

Next.js calls this at build time to know which dynamic routes to pre-render.

💻 Example

SSG with Dynamic Routes — Pre-building a blog with dynamic slugs using generateStaticParams.

tsx
import { notFound } from 'next/navigation';
import { db } from '@/lib/db';
import type { Metadata } from 'next';

interface Props {
  params: { slug: string };
}

// Tell Next.js which slugs to pre-build at build time
export async function generateStaticParams() {
  const posts = await db.post.findMany({
    select: { slug: true },
    where: { published: true },
  });
  return posts.map((post) => ({ slug: post.slug }));
}

// Generate metadata per page (also at build time)
export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const post = await db.post.findUnique({ where: { slug: params.slug } });
  return {
    title: post?.title ?? 'Post Not Found',
    description: post?.excerpt,
  };
}

export default async function BlogPostPage({ params }: Props) {
  const post = await db.post.findUnique({
    where: { slug: params.slug },
  });

  if (!post) notFound();

  return (
    <article>
      <h1>{post.title}</h1>
      <time>{post.publishedAt.toLocaleDateString()}</time>
      <div dangerouslySetInnerHTML={{ __html: post.contentHtml }} />
    </article>
  );
}

🤔 Common Confusions

❓ Does SSG mean I cannot have any dynamic content on the page?

SSG pre-builds the server-rendered HTML. You can still have Client Components with dynamic content (fetched client-side after page load). The pattern: SSG for the static shell + Client Component for user-specific data. Example: a product page (SSG) with a personalised "Recently Viewed" section (client-side fetch).

❓ What happens if a product is deleted after SSG builds the page?

The stale page will still be served until the next build or ISR revalidation. Add a notFound() check in the component — if the product no longer exists in the DB, return notFound(). With ISR, the page will be updated within the revalidation window.

❓ How long does SSG take for large sites?

Next.js parallelises SSG across CPU cores. A site with 10,000 pages typically builds in 2–5 minutes. For 1M+ pages, use ISR instead — pre-build only the most popular pages and generate the rest on first request.

🚨 Common Production Issues

Build time explosion — pre-building 100,000+ pages can take 30+ minutes. Solution: use ISR with dynamicParams = true, pre-build only the top 1,000 most-visited pages, and generate the rest on demand.

Stale content after CMS updates — SSG pages do not update until the next build. Solution: use ISR with revalidate, or configure your CMS to trigger a rebuild webhook on publish.

generateStaticParams fetching too much data — fetching full product objects when you only need slugs wastes build time and memory. Always select only the fields needed: { select: { slug: true } }.

✅ Best Practices

Use SSG as the default for all non-personalised content

Use generateStaticParams with { select: { slug: true } } — only fetch the fields needed for params

Set dynamicParams = true for large catalogs — pre-build popular pages, generate the rest on demand

Combine SSG with ISR for content that changes — pre-built but refreshed in the background

Use generateMetadata alongside generateStaticParams for per-page SEO metadata

🏛️ Architect's Note

Senior Architect's Perspective

The default-static architecture of the App Router is one of its most important design decisions. By making static the default and dynamic the opt-in, Next.js nudges teams toward the most performant architecture automatically.

For enterprise: think of SSG as your content CDN layer. Marketing sites, documentation, product catalogs — these should be 100% static. Only the authenticated, personalised parts of your app need SSR. This separation dramatically reduces infrastructure costs and improves global performance.

💬 Frequently Asked Questions

Can I use SSG with a database?

Yes — the database is queried at build time (in generateStaticParams and the page component), not at request time. The built HTML contains the data baked in. This is how headless CMS integrations work — query at build, serve static HTML.

How do I trigger a rebuild when CMS content changes?

Two approaches: (1) On-demand ISR — call revalidatePath() or revalidateTag() from a webhook endpoint when content changes. This updates specific pages without a full rebuild. (2) Deploy webhook — trigger a full next build on content publish. On-demand ISR is almost always better.

What is the difference between SSG and a plain HTML file?

SSG pages are still React apps — Client Components hydrate and become interactive. The HTML shell is pre-built, but JavaScript loads and React takes over for interactivity. A plain HTML file has no React at all.

🎯 Key Takeaways

1SSG pre-builds HTML at deploy time — served from CDN, no server cost per request
2App Router routes are static by default — you opt into dynamic rendering
3Use generateStaticParams to pre-build dynamic routes at build time
4SSG + ISR is the most common production pattern for content-heavy sites
5dynamicParams = true lets Next.js SSR unknown slugs on first request and cache them
6For 100k+ pages, pre-build only popular pages and generate the rest on demand

🎯 Practice this topic in interviews

↗ Where this topic fits

Sources

Sources / References

Use these Next.js references to verify the concept in official docs and continue into the most relevant SplashRide pages.

Related SplashRide pages

SplashRide Next.js learning path

Browse the full Next.js topic collection and learning order on SplashRide.

Next.js Interview Prep

Practice Next.js interview questions and scenario-based answers.

Frontend Engineer Career Path

A beginner-friendly journey through web foundations, React, production frontend engineering, and interview preparation.

Full Stack Java Developer Career Path

A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.

Incremental Static Regeneration (ISR)

Master ISR — the Next.js feature that gives you static performance with dynamic freshness. Learn time-based and on-demand revalidation for real production systems.

Server-Side Rendering (SSR)

Understand Server-Side Rendering in Next.js — when to use it, how it works with the App Router, and how to avoid the performance traps that catch most developers.