DEV Community

Cover image for Rendering Patterns in Next.js: CSR, SSR, SSG, ISR, RSC, PPR, and DPR
Farzan Kalantari
Farzan Kalantari

Posted on

Rendering Patterns in Next.js: CSR, SSR, SSG, ISR, RSC, PPR, and DPR

Next.js provides different rendering patterns like CSR, SSR, SSG, ISR, RSC, PPR, and DPR. In this article, we’ll go through what each means and when to use them.

Introduction:

Rendering is the process of turning code and data into a visual interface that users can interact with. In web development, the way a page is rendered plays a major role in overall performance, SEO, user experience, and scalability.
Next.js, one of the most popular React frameworks, provides several rendering strategies — including CSR (Client-Side Rendering), SSR (Server-Side Rendering), SSG (Static Site Generation), ISR (Incremental Static Regeneration), RSC (React Server Components), PPR (Partial Pre-rendering), and DPR (Dynamic Partial Rendering). Each of these techniques offers a different balance between speed, interactivity, and data freshness depending on the use case.
By understanding how these rendering methods work, developers can make informed decisions about which approach best fits their project — whether the goal is lightning-fast performance, improved SEO, or a more dynamic and interactive user experience.

Client-Side Rendering (CSR)

Definition:
In Client-Side Rendering (CSR), the server only sends a minimal HTML file with the required JavaScript bundles. Once the JavaScript is downloaded and executed in the browser, the client fetches the necessary data, hydrates the app, and renders the user interface (UI) dynamically. This makes the app very interactive, but it slows down the initial load and may negatively affect search engine optimization (SEO).

Use Case:
CSR is typically used, where user interaction is highly important and SEO is not a priority, such as:

  • User and admin dashboards
  • Chat and messaging applications
  • Online design and editing tools
  • SaaS platforms with dynamic data
  • Progressive Web Apps (PWA)

Advantages & Disadvantages:

Advantages:

  • High interactivity and smooth user experience
  • Reduced processing load on the server
  • Ability to update parts of the UI without reloading the entire page

Disadvantages:

  • Slower initial load because that need to download and execute JavaScript
  • Limitations in SEO
  • Full dependency on JavaScript execution in the browser

Example:
To implement CSR in Next.js, you must utilize the "use client" directive at the top of a file. This tells the framework to render the component on the client side rather than on the server side.

As an illustration in the next section, a simple counter is initialized with useState. Its value is stored and modified only on the client side. On a user action's click event, state is updated and UI is re-rendered without a refresh of the page. Such a response is one in which "use client" is facilitating CSR.

"use client";

import { useState } from "react";

export default function CSRExample() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <h1>Client-Side Rendering Example</h1>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click Me
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Server-Side Rendering (SSR)

Definition:
Server-Side Rendering (SSR) is a rendering strategy where the HTML content is generated on the server for every request before being sent to the client. This technique ensures better SEO, faster first meaningful paint, and enables dynamic data fetching at request time.

Use Case:
SSR is preferred for:

  • SEO-critical websites
  • E-commerce product pages
  • News and media portals
  • Content-heavy landing pages

Advantages & Disadvantages:

Advantages:

  • Better SEO
  • Faster first content display
  • Dynamic data rendering

Disadvantages:

  • Higher server load
  • Slower navigation between pages
  • Requires server for rendering

Example:
Each time the page is requested, the server generates fresh HTML content that includes the current server time before sending it to the client. This ensures that the user always sees up-to-date data rendered directly on the server.

export default async function SSRExample() {
  const time = new Date().toLocaleTimeString();

  return (
    <div>
      <h1>Server-Side Rendering Example</h1>
      <p>Current server time: {time}</p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Static-Site Generation (SSG)

Definition:
Static-Site Generation (SSG) pre-renders pages at build time (during next build) and serves the static HTML on every request. It provides excellent first-load performance, works well with CDNs, and offers strong SEO benefits.

Use Case:
SSG is preferred for:

  • Blogs and documentation
  • Marketing/landing pages
  • Catalogs that don’t update often
  • Content that benefits from global caching

Advantages & Disadvantages:

Advantages:

  • fast initial load & SEO
  • CDN-friendly & scalable
  • Low server cost at runtime

Disadvantages:

  • Stale content until rebuild or revalidate
  • Build time grows with number of pages
  • Requires strategy for dynamic data

Example:
dynamic = "force-static" → Forces the page to be generated once at build time and served as static HTML.

generateStaticParams() → Defines static routes or data that are precomputed during build.

The page is not regenerated on each request, making it very fast and CDN-friendly.

export const dynamic = "force-static"; // ensures SSG

export async function generateStaticParams() {
  // simulate static data at build time
  const posts = [{ id: 1 }, { id: 2 }];
  return posts.map((p) => ({ id: p.id.toString() }));
}

export default function BlogList() {
  return (
    <div className="text-center">
      <h1>Static Site Generation Example</h1>
      <p>This page is generated at build time.</p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Incremental-Static Regeneration (ISR)

Definition:
Incremental Static Regeneration (ISR) enables Next.js applications to serve pre-rendered static pages while also permitting updates in the background based on a revalidation interval or through explicit on-demand triggers. It combines the performance benefits of SSG with the freshness of dynamic content.

Use Case:

  • Blogs, product catalogs, documentation, or marketing sites that need regular updates
  • CMS-driven or event-triggered updates with on-demand revalidation

Advantages & Disadvantages:

Advantages:

  • Fast static-first loads
  • No full rebuild needed
  • CDN & cache friendly
  • On-demand freshness

Disadvantages:

  • Slightly stale-first request after revalidate
  • Background regeneration uses server resources
  • Only regenerates when requested
  • On-demand adds complexity

Example:
Combines SSG performance with the freshness of SSR.

The revalidate = 60 property means this page will be regenerated every 60 seconds in the background.

The next visitor gets updated content automatically.

export const revalidate = 60;

export default async function Posts() {
  const posts = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=5")
    .then((r) => r.json());

  return (
    <div>
      <h1>ISR Example</h1>
      <ul>{posts.map((p) => <li key={p.id}>{p.title}</li>)}</ul>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

React-Server Components (RSC)

Definition:
React Server Components (RSC) provide a mechanism to render components on the server without sending their JavaScript to the client. They reduce bundle size, improve performance, and enable secure server-side data access. Next.js App Router integrates RSC by default, supporting static, dynamic, and streaming server-rendering strategies.

Use Case:
RSC is ideal when:

  • You need server-side data fetching with secrets, e.g., DB access.
  • You want to reduce client JS bundle size.
  • You require fast initial load and partial streaming

Advantages & Disadvantages:

Advantages:

  • Reduced client bundle
  • Secure server-side logic
  • Efficient streaming & caching

Disadvantages:

  • No client-side state/hooks in RSC
  • Less familiar mental model
  • Mixed boundary complexity

Example:
The main page (page.tsx) is a Server Component — it runs on the server and never sends JS to the client.

LikeButton is a Client Component since it uses React state.

This hybrid model minimizes client JS, speeds up initial load, and protects server-only data (like database queries).

// app/page.tsx — default Server Component
export default async function Page() {
  const todos = await fetch(
    "https://jsonplaceholder.typicode.com/todos/1"
  ).then((r) => r.json());
  return <h1>{todos.title}</h1>;
}

// app/ui/LikeButton.tsx — Client Component
("use client");
import { useState } from "react";
export default function LikeButton({ initial }: { initial: number }) {
  const [likes, setLikes] = useState(initial);
  return <button onClick={() => setLikes(likes + 1)}>{likes}</button>;
}
Enter fullscreen mode Exit fullscreen mode

Dynamic-Partial Rendering (DPR)

Definition:
Dynamic Partial Rendering (DPR) renders only the dynamic parts of a page on request, while other sections remain static or pre- rendered. This speeds up responses and avoids full SSR when it’s not needed.

Use Case:

  • Large pages with mixed static and dynamic content.
  • Dashboards or profiles with personalized content
  • Applications where only specific parts of the page change per request.

Advantages & Disadvantages:

Advantages:

  • Optimized performance by avoiding full SSR.
  • Reduced server workload compared to rendering the entire page dynamically.
  • Better handling of time-sensitive or user-specific data.

Disadvantages:

  • More complex state management across static and dynamic areas
  • Possible inconsistencies between static and dynamic sections
  • Requires careful architectural design to prevent server overhead.

Partial Pre-Rendering (PPR)

Definition:
Partial Pre-Rendering (PPR) is a hybrid method where static parts of a page load immediately, while dynamic parts are progressively streamed and hydrated using React Suspense. This gives users instant content while waiting for updates.

Use Case:

  • Pages that are mostly static but need a few live updates
  • Blog posts or product pages with mostly stable info but dynamic details (like price/stock)
  • SEO-heavy apps that still need real-time data updates

Advantages & Disadvantages:

Advantages:

  • Improved user experience (UX) since static content appears instantly.
  • Reduced Time to First Byte (TTFB).
  • SEO-friendly because search engines can crawl the pre-rendered static parts.

Disadvantages:

  • More complex to implement since it mixes static and dynamic rendering
  • Requires correct use of React Suspense/streaming
  • Can cause layout shifts if dynamic content loads later.

Example:
Static content appears instantly, while dynamic sections (like product price) stream in later.

React Suspense handles streaming and hydration seamlessly.

import { Suspense } from "react";
import ProductDetails from "./ProductDetails";

export default function ProductPage() {
  return (
    <div>
      <h1>Partial Pre-Rendering Example</h1>
      <Suspense fallback={<p>Loading price...</p>}>
        <ProductDetails />
      </Suspense>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Rendering Pattern Comparison:

Rendering Mode Initial Perf SEO Friendliness Freshness Complexity JS Load Typical Use Cases Notes
CSR Medium to poor initially; strong after hydration Low to medium High (client) Low High Dashboards, SPA tools, interactive apps Not SEO-friendly, good for highly interactive pages after login
SSR Good (higher TTFB) High Very high Medium Medium Auth pages, live pricing, search pages SEO-friendly, dynamic content, moderate JS load
SSG Excellent (CDN) High Low (without ISR) Low Low Blogs, docs, marketing pages Very fast, ideal for public static pages, limited frequent updates
ISR Near SSG with periodic/on-demand freshness High High (interval + on-demand) Medium Low Catalogs, CMS-driven pages Combines SSG speed with content updates, supports revalidation
RSC Excellent (less client JS, streaming) High Depends on strategy Medium Very low Data-driven pages with minimal client-side JS Optimized for minimal JS and server-heavy components
PPR / DPR Very high (edge shell + streaming) High High High / Experimental Medium Personalized pages, hybrid pages Experimental, combines SSR/ISR benefits, high complexity

Conclusion:
Rendering patterns in Next.js aren’t one-size-fits-all solutions — they’re tools meant to be chosen based on what your project actually needs. For static content and strong SEO, methods like SSG or PPR usually work best. For more dynamic or real-time apps, CSR or SSR are better options. Approaches like ISR and DPR offer a nice middle ground, combining the speed of static pages with the flexibility of dynamic updates. And finally, RSC takes things a step further by pushing performance even more through server-side logic.
By learning how to use these different rendering patterns effectively, developers can build web apps that aren’t just fast and reliable, but also scalable and ready for whatever comes next.

Top comments (0)