Back to Blog
Lesson 33 of the Advanced React: Performance, Architecture & Patterns course
ReactJune 28, 20264 min read

Static Site Generation (SSG) Patterns: Architecting for Performance

Master Static Site Generation (SSG) and Incremental Static Regeneration (ISR) to shift rendering to build time and deliver lightning-fast, scalable React apps.

ReactPerformanceArchitectureSSGNext.jsWeb Developmentjavascriptfrontend

Previously in this course, we explored Streaming Server-Side Rendering to improve Time to First Byte (TTFB) by flushing HTML incrementally. While streaming SSR excels at dynamic, user-specific data, it still incurs a server-side cost for every request. This lesson introduces Static Site Generation (SSG), a pattern that trades runtime server cycles for near-instant delivery by moving rendering to build time.

Understanding Static Generation from First Principles

At its core, SSG means generating the HTML for a page at build time rather than at request time. When a user requests a static page, the server (or CDN) simply serves a pre-rendered file.

This eliminates the "cold start" of server-side logic, database queries, and component reconciliation for every request. The result is a performance profile that is essentially limited only by the speed of your CDN.

SSG vs. SSR Comparison

FeatureStatic Site Generation (SSG)Server-Side Rendering (SSR)
Rendering TimeBuild TimeRequest Time
Data FreshnessStale until next buildReal-time
Server LoadExtremely Low (CDN heavy)High (Compute heavy)
Use CaseBlogs, Marketing, DocsDashboards, User feeds

Implementing SSG Patterns

In a modern React framework (like Next.js), you implement SSG by defining how a page fetches data during the build process. Instead of fetching data inside useEffect or relying on runtime SSR functions, you use build-time data hooks.

Worked Example: Generating a Static Product Catalog

Imagine we are building a product catalog for our project. We want the product pages to be as fast as possible. We use getStaticProps (or equivalent build-time functions) to fetch the data once when the site is deployed.

JAVASCRIPT
// pages/products/[id].js

// This function runs at build time
export async function getStaticProps({ params }) {
  const product = await fetchProductFromAPI(params.id);
  
  return {
    props: { product },
    // Incremental Static Regeneration: Re-validate every 60 seconds
    revalidate: 60, 
  };
}

// This function tells the build system which paths to pre-render
export async function getStaticPaths() {
  const products = await getAllProductIds();
  const paths = products.map((id) => ({ params: { id } }));
  
  return { paths, fallback: CE9178">'blocking' };
}

export default function ProductPage({ product }) {
  return <div>{product.name} - {product.price}</div>;
}

Managing Incremental Static Regeneration (ISR)

The biggest drawback of pure SSG is that updating content requires a full site rebuild. If you have 10,000 product pages, a rebuild for a price change is inefficient.

ISR solves this by allowing you to update static pages in the background after the site is deployed. By adding a revalidate property to your build-time logic, you tell the server: "If a request comes in after X seconds, serve the cached version, but trigger a background regeneration of this page."

This gives you the best of both worlds: the performance of static files and the flexibility of dynamic updates.

Hands-on Exercise: Static Optimization

  1. Audit your current project: Identify three pages that do not contain user-specific data (e.g., "About Us," "Help Center," or a public product list).
  2. Refactor: Move the data fetching logic for these pages from useEffect into a build-time data function.
  3. Configure ISR: Set a revalidate window (e.g., 3600 seconds for one hour) to ensure your content stays fresh without needing a redeploy for minor updates.
  4. Verify: Run a production build (npm run build) and inspect the output. You should see static HTML files generated for these routes.

Common Pitfalls

  • Over-using ISR: Don't set revalidate to 1 second for highly volatile data. Use it for content that changes periodically. If you need true real-time updates, use client-side fetching with React Query instead.
  • Assuming User Context: You cannot access cookies, headers, or local storage during SSG because the page is generated on a build server, not the user's device. If a page requires user authentication, it cannot be fully static.
  • Large getStaticPaths: If you have millions of pages, building them all at once will crash your build pipeline. Use fallback: 'blocking' to generate pages on-demand the first time they are requested, rather than pre-building every single possible route.

Recap

SSG turns your React application into a set of highly optimized static files. By leveraging getStaticPaths to define your routes and revalidate to manage content freshness through ISR, you can scale your application to handle massive traffic with minimal compute cost. Remember to balance the need for performance against the need for data freshness when deciding between SSG and SSR.

Up next: We will explore Internationalization (i18n) Architecture, focusing on how to manage localized content without destroying your performance gains.

Similar Posts