NextJs
SSG and SSR

Static Site Generation (SSG) & Server-Side Rendering (SSR) in Next.js

Next.js offers different rendering strategies to optimize performance and deliver content based on various requirements. The primary rendering methods are Static Site Generation (SSG), Server-Side Rendering (SSR), and Client-Side Rendering (CSR). Here’s an in-depth look at SSG and SSR concepts, including practical examples and comparisons:


1. getStaticProps: Fetching Data at Build Time

getStaticProps allows you to fetch data at build time to generate static pages. This method is ideal for pages with content that doesn’t change often and can be pre-rendered for improved performance and SEO.

Example: Using getStaticProps

// pages/posts/[id].js
export async function getStaticProps(context) {
  const { id } = context.params;
  const res = await fetch(`https://api.example.com/posts/${id}`);
  const post = await res.json();
 
  return {
    props: { post }, // Pass data to the page component as props
    revalidate: 10,  // Optionally set ISR revalidation time in seconds
  };
}
 
export default function Post({ post }) {
  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  );
}
  • File: pages/posts/[id].js
  • Purpose: Fetch data for a specific post at build time and generate a static page.
  • Benefit: The page is pre-rendered and served as static HTML, which improves load times and SEO.

2. getServerSideProps: Fetching Data on the Server for Every Request

getServerSideProps fetches data on the server side for every request. This method is useful for pages where content changes frequently and needs to be up-to-date with each request.

Example: Using getServerSideProps

// pages/posts/[id].js
export async function getServerSideProps(context) {
  const { id } = context.params;
  const res = await fetch(`https://api.example.com/posts/${id}`);
  const post = await res.json();
 
  return {
    props: { post }, // Pass data to the page component as props
  };
}
 
export default function Post({ post }) {
  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  );
}
  • File: pages/posts/[id].js
  • Purpose: Fetch data for a specific post on each request, ensuring the page is always up-to-date.
  • Benefit: The page content is fresh and reflects the latest data from the server.

3. getStaticPaths: Dynamically Generating Paths for SSG Pages

getStaticPaths is used in conjunction with getStaticProps for dynamic routes. It defines which paths to pre-render at build time for pages that have dynamic segments.

Example: Using getStaticPaths

// pages/posts/[id].js
export async function getStaticPaths() {
  const res = await fetch('https://api.example.com/posts');
  const posts = await res.json();
 
  const paths = posts.map(post => ({
    params: { id: post.id.toString() },
  }));
 
  return {
    paths,
    fallback: 'blocking', // Handle paths not generated at build time
  };
}
 
export async function getStaticProps(context) {
  const { id } = context.params;
  const res = await fetch(`https://api.example.com/posts/${id}`);
  const post = await res.json();
 
  return {
    props: { post },
    revalidate: 10, // Optionally set ISR revalidation time in seconds
  };
}
 
export default function Post({ post }) {
  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  );
}
  • File: pages/posts/[id].js
  • Purpose: Define which dynamic paths should be pre-rendered at build time.
  • Benefit: Ensures that static pages are generated for the defined paths, improving performance and SEO.

4. Incremental Static Regeneration (ISR)

ISR allows you to update static pages after the initial build without needing to rebuild the entire site. It enables you to keep static pages up-to-date while maintaining the performance benefits of SSG.

Example: Using ISR

// pages/posts/[id].js
export async function getStaticProps(context) {
  const { id } = context.params;
  const res = await fetch(`https://api.example.com/posts/${id}`);
  const post = await res.json();
 
  return {
    props: { post },
    revalidate: 10, // Revalidate the page every 10 seconds
  };
}
  • File: pages/posts/[id].js
  • Purpose: Update static content at specified intervals.
  • Benefit: Ensures that the content is periodically refreshed while leveraging the performance benefits of static generation.

5. Revalidation in ISR

Revalidation is a feature of ISR that allows you to update static content at specific intervals. This ensures that pages stay up-to-date with minimal impact on performance.

Example: Setting Up Revalidation

// pages/posts/[id].js
export async function getStaticProps(context) {
  const { id } = context.params;
  const res = await fetch(`https://api.example.com/posts/${id}`);
  const post = await res.json();
 
  return {
    props: { post },
    revalidate: 60, // Revalidate the page every 60 seconds
  };
}
  • File: pages/posts/[id].js
  • Purpose: Define how often the static page should be revalidated.
  • Benefit: Ensures content is updated at regular intervals while maintaining fast load times.

6. Comparison: SSR vs SSG vs CSR

Understanding when to use SSR, SSG, or CSR depends on the specific needs of your application:

  • SSR (Server-Side Rendering): Use SSR when you need to fetch and render content on each request to ensure it’s always up-to-date. Suitable for dynamic content and user-specific data.

  • SSG (Static Site Generation): Use SSG for pages with content that doesn’t change often and can be pre-rendered at build time. Ideal for blog posts, documentation, and other static content.

  • CSR (Client-Side Rendering): Use CSR for pages where client-side JavaScript is sufficient to fetch and render data, such as user dashboards or single-page applications with dynamic interactions.

Example Use Cases:

  • SSR: A user profile page where content changes frequently based on user interactions.
  • SSG: A blog page where posts are static and don’t change often.
  • CSR: An interactive dashboard that fetches data using client-side JavaScript.

7. Fallback in getStaticPaths

The fallback key in getStaticPaths controls the behavior for paths not generated at build time:

  • fallback: false: Only the paths returned by getStaticPaths are generated. Requests to other paths will result in a 404 error.

  • fallback: true: New paths will be generated on-demand, serving a static shell while the page is generated. The generated page will be cached and served on subsequent requests.

  • fallback: 'blocking': Similar to true, but blocks the request until the new page is generated. The user will see the fully rendered page on the first request.

Example: Using Fallback

// pages/posts/[id].js
export async function getStaticPaths() {
  const res = await fetch('https://api.example.com/posts');
  const posts = await res.json();
 
  const paths = posts.map(post => ({
    params: { id: post.id.toString() },
  }));
 
  return {
    paths,
    fallback: 'blocking', // Handle new paths by blocking until the page is generated
  };
}
  • File: pages/posts/[id].js
  • Purpose: Handle paths that were not pre-rendered at build time.
  • Benefit: Allows dynamic path generation while maintaining performance.