Skip to main content

Rendering Pattern

What It Is

Rendering pattern means deciding where and when a page is generated and where data is fetched.

In Next.js, CSR, SSR, and SSG solve the same problem, but they differ in timing, execution place, initial HTML, SEO, and performance.

Rendering Pattern = When + Where data is fetched and shown on the UI

Rendering Categories

Rendering patterns are mainly split between client and server.

Client -> CSR

Server -> SSR / SSG

App Router -> React Server Components + Client Components

In simple terms:

  • CSR renders in the browser.
  • SSR renders on the server for every request.
  • SSG renders at build time.
  • RSC runs components on the server by default.
  • Client Components are used when interactivity is needed.

Client-Side Rendering

CSR stands for Client-Side Rendering.

In CSR, the page first loads in the browser, then JavaScript fetches data and renders the UI.

Users may initially see a loading state before the real content appears.

CSR = Browser loads page shell -> JS fetches data -> Browser renders UI

CSR Example

import { useEffect, useState } from "react";

export default function CsrPage() {
const [data, setData] = useState(null);

useEffect(() => {
fetch("http://localhost:3000/courses")
.then((res) => res.json())
.then(setData);
}, []);

if (!data) return <p>Loading...</p>;

return (
<div>
{data.map((course) => (
<h2 key={course.id}>{course.title}</h2>
))}
</div>
);
}

CSR Use Case

CSR is best suited for highly interactive UI.

Good examples:

  • dashboards
  • filters
  • search pages
  • UI where data depends on user actions

CSR downside:

  • slower initial content load
  • weaker SEO because content is not present in the initial HTML

Server-Side Rendering

SSR stands for Server-Side Rendering.

In SSR, data is fetched on the server for every request.

The server sends fully rendered HTML to the browser, so users see complete content earlier.

SSR = Request -> Server fetches data -> Server renders HTML -> Browser receives content

SSR Example

export async function getServerSideProps() {
const res = await fetch("http://localhost:3000/courses");
const data = await res.json();

return {
props: { data },
};
}

export default function SsrPage({ data }) {
return (
<div>
{data.map((course) => (
<h2 key={course.id}>{course.title}</h2>
))}
</div>
);
}

SSR Use Case

SSR is useful when:

  • data changes frequently
  • SEO is important
  • page content should be fresh per request

SSR tradeoff:

  • higher server load
  • slower response than static pages because rendering happens per request

Static Site Generation

SSG stands for Static Site Generation.

In SSG, data is fetched at build time and static HTML files are generated.

Those static files are then served quickly to users.

SSG = Build time data fetch -> Static HTML generated -> Browser receives static page

SSG Example

export async function getStaticProps() {
const res = await fetch("http://localhost:3000/courses");
const data = await res.json();

return {
props: { data },
};
}

export default function SsgPage({ data }) {
return (
<div>
{data.map((course) => (
<h2 key={course.id}>{course.title}</h2>
))}
</div>
);
}

SSG Use Case

SSG is ideal for content that does not change often.

Good examples:

  • blogs
  • marketing pages
  • public content
  • documentation pages

SSG is usually the fastest option because the page is already generated.


Incremental Static Regeneration

ISR stands for Incremental Static Regeneration.

ISR allows a static page to update in the background after a specific time.

revalidate: 60;

This is useful when you want static page speed but still need occasional content updates.

SSG = static until rebuild
ISR = static page + background updates

CSR vs SSR vs SSG

FeatureCSRSSRSSG
ExecutionBrowserServer per requestBuild time
Data FetchingAfter initial renderBefore response is sentDuring build
Initial HTMLMinimal shellFully populated HTMLStatic pre-rendered HTML
TTFBFast shellSlower due to server processingVery fast
LCPSlower because content depends on JSGood because HTML contains contentBest because content is pre-generated
HydrationFull app hydrationHTML + hydrationStatic HTML + hydration
SEOWeakStrongStrong
CachingBrowser cache / client stateNeeds explicit cachingNaturally cacheable with CDN
ScalabilityHigh client-side loadLimited by server capacityExtremely high
FreshnessReal-time client fetchFresh per requestStale unless rebuilt or ISR is used
Best FitInteractive apps and dashboardsDynamic content and personalizationBlogs, marketing pages, public content
Worst FitSEO-heavy pagesHigh-traffic static pagesFrequently changing real-time data

React Server Components

In Next.js App Router, components run on the server by default.

This means no JavaScript is sent to the browser unless it is needed.

RSC improves performance by moving data fetching and rendering to the server.

Server Component = Data fetching + rendering on server

Server Component Example

export default async function Page() {
const res = await fetch("http://localhost:3000/courses");
const courses = await res.json();

return (
<div>
{courses.map((course) => (
<h2 key={course.id}>{course.title}</h2>
))}
</div>
);
}

Server Component behavior:

  • data is fetched on the server
  • no client JavaScript is sent for this part
  • initial render is fast

Client Components

Client Components are used when browser interactivity is needed.

To create a Client Component, use:

"use client";

Client Components can handle:

  • state
  • events
  • input changes
  • user interactions

Client Component Example

"use client";

import { useState } from "react";

export default function Filter() {
const [query, setQuery] = useState("");

return (
<input
placeholder="Search courses..."
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
);
}

Client Component tradeoff:

  • enables interactivity
  • increases bundle size
  • requires hydration

Combined Server and Client Usage

A common pattern is to fetch and render data on the server, then use Client Components only for interactive parts.

import Filter from "./Filter";

export default async function Page() {
const res = await fetch("http://localhost:3000/courses");
const courses = await res.json();

return (
<div>
<Filter />

{courses.map((course) => (
<h2 key={course.id}>{course.title}</h2>
))}
</div>
);
}
Server -> data + rendering
Client -> interaction

This keeps the page fast while still allowing interactive UI.


How to Choose

NeedBest Pattern
Highly interactive UICSR
Fresh data on every requestSSR
SEO with dynamic dataSSR
Static public contentSSG
Static speed with periodic updatesISR
Less JavaScript and server-side data fetchingRSC
State, events, and browser interactionClient Component

Basic Checklist

Use CSR for interactive dashboards and filters
Use SSR when data changes often or SEO matters
Use SSG for blogs, marketing pages, and public content
Use ISR when static pages need background updates
Use Server Components for server-side data and less client JS
Use Client Components only when interactivity is needed
Avoid sending unnecessary JavaScript to the browser
Choose rendering based on freshness, SEO, interactivity, and scalability

Interview Style Answer

Rendering patterns define where and when a page is generated and where data is fetched. CSR renders in the browser after JavaScript loads, so it is useful for highly interactive pages but weaker for SEO and initial load. SSR fetches data and renders HTML on the server for every request, giving fresh content and better SEO but increasing server load. SSG fetches data at build time and serves static HTML, making it very fast and scalable for blogs, marketing pages, and public content. ISR extends SSG by allowing static pages to update in the background. In Next.js App Router, React Server Components run on the server by default to reduce client JavaScript, while Client Components with "use client" are used for interactivity like state and events.


One-Line Summary

Rendering Pattern = Choose CSR, SSR, SSG, ISR, RSC, or Client Components based on SEO, freshness, interactivity, and performance.

Final Mental Model

CSR -> Browser renders
SSR -> Server renders per request
SSG -> Build generates static HTML
ISR -> Static HTML updates in background
RSC -> Server component by default
Client Component -> Browser interactivity