How Static Site Generation (SSG) Works in Next.js

SSG (Static Site Generation) is a rendering strategy where HTML pages are generated once at build time (next build). After deployment these pages are served as regular static files via CDN.

How It Works

1

Build (next build)

Next.js calls the server component or getStaticProps, runs all API/DB requests and generates HTML files for each page.

2

Deploy

The ready HTML files are placed on a CDN. The server no longer participates in page generation.

3

User request

When a user opens a page, the CDN instantly serves the ready HTML. No waiting for the server, no real-time rendering.

SSG in App Router

In the App Router (Next.js 13+) SSG is the default behavior. If a component does not use dynamic data, Next.js will automatically generate it statically:

// app/docs/page.tsx
// This page will be statically generated at build time
export default async function DocsPage() {
  const res = await fetch('https://api.hackfrontend.com/docs')
  const docs = await res.json()

  return (
    <ul>
      {docs.map((doc: { slug: string; title: string }) => (
        <li key={doc.slug}>{doc.title}</li>
      ))}
    </ul>
  )
}

By default fetch in server components caches the result. This is the equivalent of SSG: the request runs once at build time.

Dynamic Routes

For dynamic pages you need to specify which paths to generate in advance. Use generateStaticParams for this:

// app/docs/[slug]/page.tsx
export async function generateStaticParams() {
  const res = await fetch('https://api.hackfrontend.com/docs')
  const docs = await res.json()

  return docs.map((doc: { slug: string }) => ({
    slug: doc.slug
  }))
}

export default async function DocPage({
  params
}: {
  params: { slug: string }
}) {
  const res = await fetch(
    `https://api.hackfrontend.com/docs/${params.slug}`
  )
  const doc = await res.json()

  return (
    <article>
      <h1>{doc.title}</h1>
      <div>{doc.content}</div>
    </article>
  )
}

At build time Next.js calls generateStaticParams, gets the list of slugs and generates a separate HTML file for each.

SSG in Pages Router (Legacy)

In the Pages Router SSG uses getStaticProps:

// pages/docs/index.tsx
export async function getStaticProps() {
  const res = await fetch('https://api.hackfrontend.com/docs')
  const docs = await res.json()

  return {
    props: { docs }
  }
}

export default function DocsPage({ docs }) {
  return (
    <ul>
      {docs.map(doc => (
        <li key={doc.slug}>{doc.title}</li>
      ))}
    </ul>
  )
}

For dynamic routes getStaticPaths is also needed:

// pages/docs/[slug].tsx
export async function getStaticPaths() {
  const res = await fetch('https://api.hackfrontend.com/docs')
  const docs = await res.json()

  return {
    paths: docs.map(doc => ({ params: { slug: doc.slug } })),
    fallback: false
  }
}

export async function getStaticProps({ params }) {
  const res = await fetch(
    `https://api.hackfrontend.com/docs/${params.slug}`
  )
  const doc = await res.json()

  return { props: { doc } }
}

When to Use SSG

Good for:

  • Documentation (like on Hack Frontend)
  • Blogs and articles
  • Landing pages, marketing sites
  • FAQ, reference sections
  • Product catalogs that update infrequently

Not suitable for:

  • Pages with personalized content (profile, dashboard)
  • Data that changes every second (stock prices, chats)
  • Pages that depend on cookies or request headers

Interview tip:

A common question: "What if the data becomes stale after the build?". Answer: that is what ISR (Incremental Static Regeneration) is for. It lets you update static pages without a full rebuild.

Benefits of SSG

  • Speed. Ready HTML is served instantly. No server wait time.
  • SEO. Search bots get the full HTML content right away.
  • Reliability. Static files do not depend on database or API availability at request time.
  • Cost. CDN hosting is cheaper than server-side rendering on every request.

Useful Resources