SSR vs SSG: Choosing the Rendering Strategy That Fits Your Performance Goals
SSR and SSG have different performance characteristics, infrastructure requirements, and use cases. Here's how to choose the right rendering strategy for your specific situation.

James Ross Jr.
Strategic Systems Architect & Enterprise Software Developer
The Rendering Decision That Defines Your Performance Profile
How you render pages — on the server for each request, statically at build time, or on the client in the browser — is one of the most consequential architectural decisions in a web application. It determines your TTFB, your LCP floor, your infrastructure complexity, and how you handle dynamic personalized content.
The frustrating thing about the SSR vs SSG debate is that both camps are right about the trade-offs they cite. SSG is faster for static content; SSR is more flexible for dynamic content. The answer is almost always a hybrid approach, but knowing which parts of your application should use which strategy requires understanding what each mode actually does.
How Each Mode Works
Static Site Generation (SSG): Pages are rendered to HTML at build time. The output is a collection of static HTML, CSS, and JavaScript files. Requests are served directly from a CDN with no server-side compute at request time.
Server-Side Rendering (SSR): Pages are rendered on the server for each request. The server fetches data, renders the page to HTML, and sends it to the browser. TTFB includes the time to fetch data and render.
Client-Side Rendering (CSR): The server sends a minimal HTML shell and JavaScript bundle. The browser downloads and executes the JavaScript, which fetches data and renders the page. The user sees nothing until the JavaScript has executed.
Incremental Static Regeneration (ISR / Nuxt SWR): A hybrid of SSG and SSR. Pages are statically generated but can be regenerated in the background at a configurable interval. Stale content is served immediately (good TTFB), and the background regeneration updates the cache for the next visitor.
Performance Characteristics by Mode
SSG performance:
TTFB: typically 20-100ms (CDN edge response, no compute) LCP: excellent — the HTML contains all content, the browser can render immediately INP: depends on JavaScript loaded on the client Freshness: data is current as of the last build
SSG is the fastest possible response time for content that doesn't change with each request. A CDN serving a static HTML file with proper caching is hard to beat.
SSR performance:
TTFB: 100ms-2000ms+ depending on server performance, database queries, and geographic distance to origin LCP: good to excellent — content is in the HTML, browser can render quickly after receiving the document INP: depends on client-side JavaScript Freshness: always current (data fetched on each request)
SSR trades TTFB for freshness. The TTFB is always higher than SSG because there's compute involved, but the content is always up-to-date.
CSR performance:
TTFB: fast (sending a minimal shell) LCP: poor — the LCP element doesn't exist in the HTML; it's created by JavaScript execution INP: depends on JavaScript efficiency, but the hydration cost is paid upfront Freshness: always current
CSR is the worst default for Core Web Vitals. LCP requires JavaScript to execute before the main content appears. For content-heavy applications, CSR creates poor scores that are hard to compensate for.
When to Use SSG
Use SSG for content that meets all three criteria:
- Does not require per-request personalization. The same HTML is served to every user (or every user in a given locale/variant).
- Does not change more frequently than your acceptable staleness threshold. A marketing page that changes twice a week can regenerate on every content update. A news site with 500 updates per day may need SSR or ISR.
- Does not have a build time that creates deployment bottlenecks. A site with 100,000 pages may take 30 minutes to rebuild. If you're making frequent content updates, ISR or SSR may be more practical.
Examples that work well with SSG: marketing sites, documentation, blogs, product landing pages, e-commerce category and product pages (with ISR), and portfolio sites.
When to Use SSR
Use SSR for content that requires:
Per-request personalization. If the page shows different content based on who the user is, what they've done, or what their account state is, SSG can't serve it (without significant complexity). SSR renders the personalized content on the server.
Real-time data. If the page displays data that changes continuously and showing stale content is not acceptable (financial dashboards, live inventory, social feeds), SSR ensures the data is fresh on each request.
A/B testing at the page level. Serving different variants to different users at the HTML level (not just client-side element toggling) requires server-side rendering.
The performance trade-off of SSR is TTFB. You can minimize this trade-off with:
- Edge rendering (Cloudflare Workers, Vercel Edge Functions) — compute close to the user, not on a centralized origin
- Streaming HTML (React Suspense, Nuxt streaming) — send the HTML shell immediately, stream dynamic parts as they become available
- Aggressive database caching — reduce the time the server spends waiting for data
ISR: The Hybrid That Works for Most Content
Incremental Static Regeneration (and Nuxt's swr route caching) threads the needle between SSG and SSR for content that changes occasionally but not on every request.
With ISR, you configure a revalidation period:
// Next.js
export const revalidate = 300 // 5 minutes
// Nuxt
export default defineEventHandler(async (event) => {
setHeader(event, 'Cache-Control', 'max-age=0, s-maxage=300, stale-while-revalidate')
// ...
})
The first request after the period expires serves the stale content immediately and triggers a background regeneration. The next request gets the fresh content. Users never wait for the regeneration.
For most content-driven applications — e-commerce, content sites, SaaS dashboards with data that's updated periodically — ISR provides near-SSG performance with near-SSR freshness.
Islands Architecture: The Advanced Model
Islands architecture (popularized by Astro, available in Nuxt and others) takes the hybrid approach further: render everything static by default, and selectively hydrate only the components that require interactivity.
A product page might be:
- Static: product images, title, description, specifications (no JavaScript at all)
- Interactive island: size selector and add-to-cart button (hydrated, interactive)
- Interactive island: reviews with infinite scroll (hydrated, fetches data client-side)
This approach produces the smallest possible JavaScript payload — only the interactive components ship JavaScript to the browser. Static content ships zero JavaScript. LCP is excellent (content in HTML), INP is minimal (only a few isolated components are interactive), and total JavaScript is a fraction of a fully hydrated SPA.
Islands architecture requires either an islands-native framework (Astro) or a framework that supports partial hydration (Nuxt with <ClientOnly>, React Server Components).
Matching Strategy to Content Type
For a typical web application:
| Content Type | Recommended Strategy |
|---|---|
| Marketing pages, documentation | SSG |
| Blog posts, articles | SSG or ISR |
| E-commerce product pages | ISR (5-60 minute revalidation) |
| Dashboard overview (aggregated data) | ISR or SSR with caching |
| User account page | SSR (personalized) |
| Real-time data view | SSR + client-side polling |
| Admin panel | CSR or SSR (authenticated, no SEO requirement) |
The answer for most real applications is "mostly SSG with ISR, SSR for authenticated/personalized pages." Pure CSR should be the exception, not the default.
The rendering strategy decision is architectural — it's hard to change once the application is built, and it determines your performance ceiling. If you're starting a new application or evaluating a rendering approach change, book a call at calendly.com/jamesrossjr and let's think through what fits your specific requirements.