Skip to content

Static Site Generation (SSG) Patterns

Static Site Generation (SSG) pre-renders pages at build time, delivering fully rendered HTML to users for improved performance, SEO, and scalability. This pattern is ideal for content that doesn’t change frequently, such as blogs, documentation, or product catalogs. Next.js provides robust tools like getStaticProps, getStaticPaths, and incremental static regeneration (ISR) to implement SSG effectively.


Pre-Rendering with getStaticProps and getStaticPaths

Pre-rendering generates static HTML for all routes at build time. This is achieved using the getStaticProps and getStaticPaths functions, which define how data is fetched and which routes are pre-rendered.

Example: Blog Posts

// pages/posts/[id].js
export async function getStaticPaths() {
  // Fetch all posts from the database
  const posts = await fetchPosts();
  return {
    paths: posts.map(post => ({ params: { id: post.id } })),
    fallback: false, // Only pre-render existing paths
  };
}

export async function getStaticProps({ params }) {
  const post = await fetchPost(params.id);
  return { props: { post } };
}
  • getStaticPaths defines which routes are pre-rendered. It can return a list of paths or use fallback: true to dynamically generate paths during requests.
  • getStaticProps fetches data for a specific route and passes it to the page component.

Diagram:

[Build Time] -> getStaticPaths() -> getStaticProps() -> Render HTML -> [Server/CDN]


Incremental Static Regeneration (ISR)

ISR allows pages to be regenerated on-demand after deployment, combining the benefits of SSG and SSR. Pages are cached and revalidated at intervals or triggered by events (e.g., API calls).

Example: Dynamic Content

// pages/products/[id].js
export async function getStaticProps({ params }) {
  const product = await fetchProduct(params.id);
  return { props: { product }, revalidate: 10 }; // Revalidate every 10 seconds
}
  • revalidate specifies how often the page is regenerated (in seconds). If the data changes frequently, this ensures users see the latest content.
  • ISR is ideal for content like product inventories or news feeds that require occasional updates.

Diagram:

[Request] -> [Cache Hit] -> Serve HTML  
[Cache Miss] -> [Regenerate] -> [Cache Update] -> Serve HTML


Route-Level SSG

Route-level SSG generates pages at build time for specific routes, optimizing for large sites with many static pages. This is particularly useful for content like product catalogs or documentation.

Example: Product Catalog

// pages/products/[category].js
export async function getStaticProps({ params }) {
  const products = await fetchProductsByCategory(params.category);
  return { props: { products } };
}
  • Pages are pre-rendered during the build process, ensuring fast load times for all routes.
  • Use fallback: true to handle routes that aren’t pre-rendered, falling back to SSR for dynamic content.

Diagram:

[Build Time] -> Generate HTML for /products/electronics, /products/books, etc.  
[Request] -> [Serve Pre-Rendered HTML]


Key Takeaways

  • SSG pre-renders pages at build time, improving performance and SEO for static content.
  • ISR dynamically regenerates pages after deployment, balancing speed and freshness.
  • Route-level SSG optimizes large sites by pre-rendering specific routes, ensuring scalability.
  • Use getStaticProps and getStaticPaths to define data fetching and route generation logic.
  • Combine SSG with ISR for hybrid workflows, ensuring fast load times while supporting dynamic updates.