Rendering Strategies: SSR, SSG, ISR and CSR

Beginner
11 min

Rendering Strategies: SSR, SSG, ISR and CSR

Every page in Next.js is rendered somewhere, at some time: per request on the server, once at build time, on a schedule, or in the browser. After this lesson you will be able to name the four strategies, tell which one the App Router picked for a route, and switch between them deliberately.

The Four Strategies at a Glance

| Strategy | When HTML is produced | Best for | |---|---|---| | SSG (Static Site Generation) | Once, during next build | Marketing pages, docs, blog posts | | ISR (Incremental Static Regeneration) | At build, then regenerated after a time window | Catalogs, news listings | | SSR (Server-Side Rendering) | On the server for every request | Dashboards, personalised pages | | CSR (Client-Side Rendering) | In the browser after JavaScript loads | Live widgets, browser-only data |

Each route decides for itself, and the App Router chooses automatically based on what your code does.

Static Rendering (SSG)

A route is statically rendered when its HTML can be produced without knowing anything about the incoming request. The result is written to disk during next build and served from a CDN.

tsx
// app/products/page.tsx export default async function ProductsPage() { const res = await fetch("https://api.example.com/products", { cache: "force-cache" }); const products: { id: string; name: string }[] = await res.json(); return <ul>{products.map((p) => <li key={p.id}>{p.name}</li>)}</ul>; }

Since Next.js 15, fetch is not cached by default. cache: "force-cache" marks the response as reusable, so the page can be pre-rendered. Run next build and check the route table: static routes are marked ○ (Static).

Incremental Static Regeneration (ISR)

Static pages go stale. ISR keeps static speed while refreshing periodically. Give the fetch a revalidate window, or set one for the whole route:

tsx
// per request const res = await fetch("https://api.example.com/products", { next: { revalidate: 3600 } }); // or per route segment export const revalidate = 3600; // seconds

The first request after 3600 seconds still receives the old HTML instantly; Next.js regenerates the page in the background and serves the fresh version to the next visitor.

Dynamic Rendering (SSR)

A route becomes dynamically rendered the moment it touches request-time information. Any of these opt a route in automatically:

  • Reading cookies(), headers() or the searchParams prop
  • Calling fetch without caching (the default)
  • Calling connection() from next/server
  • Exporting export const dynamic = "force-dynamic"
tsx
// app/dashboard/page.tsx import { cookies } from "next/headers"; export default async function Dashboard() { const store = await cookies(); // request-time API => dynamic route const theme = store.get("theme")?.value ?? "light"; return <p>Your theme is {theme}</p>; }

Dynamic routes show as ƒ (Dynamic) in the build output. cookies() and headers() are asynchronous and must be awaited.

Client-Side Rendering (CSR)

Client Components are still server-rendered for their initial HTML, but data they load in useEffect or with a library such as SWR arrives in the browser after hydration. Use this for browser-only state or values that change every few seconds. Never rely on it for content search engines must index.

Choosing a Strategy

  • Start static; most pages need no request data.
  • Add revalidate when data changes but not per user.
  • Go dynamic only for per-request content, and keep that part small.

Common mistakes

  • Forgetting cache: "force-cache" and wondering why a simple page is dynamic.
  • Reading cookies() in the root layout, which makes every route dynamic.
  • Fetching SEO-critical content in useEffect, so crawlers see an empty shell.
Quick Quiz
Question 1 of 3

Which of these makes a route dynamically rendered in the App Router?

Key Takeaways

  • Next.js picks a rendering strategy per route: static by default, dynamic when request data is used.
  • fetch is uncached by default; cache: "force-cache" or next: { revalidate } allows static rendering.
  • ISR serves stale HTML instantly and regenerates in the background after the window expires.
  • cookies(), headers(), searchParams and force-dynamic opt a route into SSR.
  • Use client-side fetching for browser-dependent or rapidly changing data, not for SEO content.

Next lesson: File-Based Routing with the App Router — see how folders and special files inside app/ become URLs.

Rendering Strategies: SSR, SSG, ISR and CSR - Next.js | CodeYourCraft | CodeYourCraft