Every web page ends up as HTML in a browser. The only real question is who builds that HTML, and when. Answer it differently and you get four strategies with four very different trade-offs.

The race
Same page, same data, four strategies. Watch two moments per lane: when content becomes visible, and when the button becomes clickable. Then switch to the budget phone.
CSR · Client-side rendering
data: always fresh
SSR · Server-side rendering
data: always fresh
SSG · Static site generation
data: as of last build
ISR · Incremental static regeneration
data: ≤ revalidate window
CSR — client-side rendering
The server sends an almost empty HTML file and a JavaScript bundle. The browser downloads and runs the JS, which fetches data and builds the page. This is the classic single-page app (Create React App, plain Vite SPA).
- Good for: dashboards and apps behind a login, where SEO doesn't matter and users stay a long time.
- Weak at: first load on slow devices, SEO, link previews — the initial HTML has no content.
SSR — server-side rendering
For every request, the server fetches data and renders full HTML. The browser shows content as soon as it arrives, then downloads JS and hydrates it.
- Good for: personalised or always-fresh pages — search results, feeds, prices.
- Weak at: server cost and TTFB under load; still ships hydration JS.
SSG — static site generation
Pages are rendered once at build time and uploaded to a CDN. Every visitor gets the same pre-made file from a server near them. This blog is statically generated.
- Good for: blogs, docs, marketing and portfolio pages — content that changes rarely.
- Weak at: data that changes often; thousands of pages mean longer builds.
ISR — incremental static regeneration
Static speed with a refresh policy. The page is served from cache; after the revalidate window, the next visitor triggers a background rebuild and later visitors see the fresh version.
// Regenerate this page at most once every 60 seconds
export const revalidate = 60;
export default async function Product({ params }) {
const { id } = await params;
const product = await getProduct(id);
return <ProductView product={product} />;
}Quick check
An e-commerce product page: prices change a few times a day, SEO matters a lot. Best default?
How to choose
Ask three questions
- Does it need to rank on Google or look good when shared? → avoid pure CSR.
- Is it the same for every visitor? → SSG or ISR. Personalised? → SSR or CSR.
- How fresh must the data be? → seconds: SSR. Minutes/hours: ISR. Until next deploy: SSG.
You don't pick one strategy for a whole site anymore — you pick one per page.
Rendering choices directly move your Core Web Vitals (LCP, INP) and your crawl-ability. To see what happens on the wire before any of this, read what happens when you type a URL.


