Understand server-side rendering, static generation and client-side rendering: how each works, trade-offs, and how to pick one per page.
In this article
Static generation builds each page once, ahead of time, and serves the same HTML to everyone. Server-side rendering builds the page on the server for each request, so it can include fresh or personalised data. Client-side rendering sends a small shell and lets the browser build the page with JavaScript. Use static generation for content that changes rarely, server rendering when the page must be current or personalised and also needs to be readable by search engines, and client rendering for interactive screens behind a login.
The three terms are often presented as rivals, but a well-built product normally uses all of them, page by page. The skill lies in matching the method to what each page is for. Here is how each works, what it costs, and how to choose.
Client-side rendering (CSR)
With CSR, the server returns a minimal HTML document and a JavaScript bundle. The browser runs the bundle, requests data from an API, and builds the interface. This is the classic single page application model.
Where it fits
- Dashboards, admin panels and tools behind a login.
- Highly interactive screens such as editors, charts and boards.
- Products where search visibility of the app screens is irrelevant.
What to watch
The visitor sees little until the JavaScript has downloaded, executed and fetched its data. On a fast laptop that is barely noticeable. On a mid-range phone with a weak signal it can feel slow. Public content rendered this way is also harder for crawlers and link previews to read reliably.
Server-side rendering (SSR)
With SSR, the server runs your component code for each request, fetches the data and returns complete HTML. The browser shows it immediately, then "hydrates" it, which means JavaScript attaches to the existing HTML to make it interactive.
Where it fits
- Pages that depend on the request: a logged-in user's account summary, localised content, or results based on query parameters.
- Pages with data that changes too often to pre-build, such as stock availability.
- Public pages that need current data and good search visibility.
What to watch
Every request costs server time, so response speed depends on your back end and database. A slow query now delays the whole page. Caching strategy becomes part of the design. You also need server capacity that scales with traffic, which means hosting is no longer just static files.
Static site generation (SSG)
With SSG, pages are built once at deploy time. The result is plain HTML files that can sit on a content delivery network (CDN) close to the visitor. There is no per-request computation.
Where it fits
- Marketing pages, documentation, blog articles and landing pages.
- Catalogue pages that change only when someone edits them.
- Anything where the same content is shown to everyone.
What to watch
Content is only as fresh as the last build. If an editor fixes a typo, the site must rebuild or use a revalidation mechanism. With thousands of pages, full rebuilds can become slow, which is why frameworks offer incremental approaches that rebuild only what changed.
Side-by-side comparison
| Aspect | Static (SSG) | Server (SSR) | Client (CSR) |
|---|---|---|---|
| HTML built | At build time | On each request | In the browser |
| Data freshness | As of last build or revalidation | Current at request time | Current after the API call |
| Personalisation | Limited without client code | Straightforward | Straightforward |
| Search and previews | Excellent | Excellent | Weaker, needs care |
| Hosting | Files on a CDN | Needs server runtime | Files on a CDN plus an API |
| Server load | Almost none | Grows with traffic | Only API load |
| Typical use | Marketing, docs, blog | Account and dynamic public pages | Dashboards, tools |
Hybrid approaches you will hear about
Incremental static regeneration serves a pre-built page but refreshes it in the background after a set time or when you trigger it. It suits large catalogues and article libraries where full rebuilds would be wasteful.
Streaming and partial rendering send the static parts of the page immediately and fill in slower, dynamic sections as their data arrives. A product page might show the description straight away while stock levels load a moment later.
Islands architecture ships HTML for the whole page but hydrates only the interactive components, such as a search box or a carousel. This reduces the JavaScript the browser must run.
Frameworks such as Next.js let you choose per route. That freedom is useful, but it means someone must make the choice deliberately for each page type. We compare the framework option with a plain single page application in Next.js vs React SPA.
A short example
In the Next.js App Router, a page's behaviour follows how it fetches data. This page is cached and effectively static, refreshed at most once an hour:
// app/guides/page.tsx
export default async function Guides() {
const res = await fetch("https://api.example.com/guides", {
next: { revalidate: 3600 },
});
const guides = await res.json();
return (
<ul>
{guides.map((g) => <li key={g.id}>{g.title}</li>)}
</ul>
);
}
And this one is rendered fresh for every request because it opts out of caching:
// app/account/page.tsx
export default async function Account() {
const res = await fetch("https://api.example.com/me", {
cache: "no-store",
// in real code, pass the user's session credentials here
});
const me = await res.json();
return <h2>Welcome back, {me.name}</h2>;
}
Defaults for caching have changed between Next.js versions, so always confirm the behaviour in the official documentation for the version you are using rather than relying on memory.
How to choose for each page
- Is the content identical for every visitor? Use static generation, with revalidation if it changes occasionally.
- Does it depend on who is asking or on live data? Use server rendering, or render a static shell and fetch the personal parts on the client.
- Must search engines or link previews see it? Avoid pure client rendering for that page.
- Is it a complex interactive tool after login? Client rendering is usually fine and simpler.
- How will it behave under a traffic spike? Static pages from a CDN cope easily. Server-rendered pages need capacity and caching.
Common mistakes
- Server-rendering pages that never change. This spends server time and adds latency for no benefit.
- Statically generating personalised pages. The risk is showing one person's data to another through a shared cache. Anything user-specific must not be cached publicly.
- Fetching everything in the browser by default. This adds round trips and a loading state to pages that could have arrived complete.
- Forgetting that hydration costs time. A page can look ready but ignore taps for a moment while JavaScript attaches. Keep interactive code lean.
- Using one mode for the whole site. The best results usually come from mixing modes.
- No plan for content updates. If editors expect changes to appear instantly but the site only rebuilds nightly, expect support requests. Agree the update path up front, perhaps with a headless CMS that triggers rebuilds.
- Skipping measurement. The effect of each choice shows up in user-focused metrics, which we explain in our Core Web Vitals guide.
Put it into practice
A useful exercise is to list every page type in your product on a sheet and mark each as "same for everyone", "personal", or "interactive tool", then note how often its content changes and whether it must be found in search. The rendering method usually becomes obvious from that sheet. If you would like an experienced team to do this mapping with you and build the result, see our web application development service, which includes server-side rendering with Next.js and single page applications.
Share this article
General educational information, not legal or professional advice for your specific situation.
