Rendering Strategies: CSR vs SSR vs SSG vs ISR

Understanding the four main rendering strategies in modern web development and when to use each.

Quick Navigation: CSR SSR SSG ISR Comparison Hybrid

The Four Rendering Strategies

Modern web applications use different rendering strategies depending on their needs. Each has trade-offs in terms of performance, SEO, complexity, and user experience.

  • CSR (Client-Side Rendering): JavaScript renders everything in the browser
  • SSR (Server-Side Rendering): Server generates HTML on each request
  • SSG (Static Site Generation): HTML generated at build time
  • ISR (Incremental Static Regeneration): SSG with periodic updates

Client-Side Rendering (CSR)

Single-Page Application (SPA) - One HTML file loads once, JavaScript handles all rendering and navigation.

How CSR Works

1
User visits URL in browser
2
Browser requests page from server
3
Server returns static files (HTML, CSS, JS) - only once
4
JavaScript executes, fetches data, renders UI at runtime
5
Subsequent navigations only fetch data (no full page reload)

Key Point: Static files loaded once, only data fetched on navigation

Advantages

  • Blazing fast navigation: Only data fetched, no full page reloads
  • Decoupled: Frontend and backend can be developed independently
  • Rich interactivity: Smooth transitions, instant feedback
  • Extendable: Same codebase can work for mobile/desktop apps
  • Lower server load: Server only serves static files

Disadvantages

  • Poor SEO: Search engines struggle with JavaScript-rendered content
  • Slower initial load: Must download and parse all JavaScript first
  • Security risks: More vulnerable to XSS attacks
  • Memory usage: Heavy JavaScript can cause memory issues
  • Blank screen: Users see blank page until JS loads

🎯 Best For:

Highly interactive apps (dashboards, admin panels, real-time apps), authenticated users, applications where SEO isn't critical, and SPAs with rich client-side interactions.

Server-Side Rendering (SSR)

Multi-Page Application (MPA) - Each navigation generates a new HTML page on the server.

How SSR Works

1
User visits URL in browser
2
Browser sends request to server
3
Server generates HTML with data populated
4
Browser receives complete HTML
5
Page renders immediately

⚠️ Key Point: Each navigation = New server request + New HTML page

Advantages

  • Better SEO: Search engines can crawl pre-rendered HTML with meta tags
  • Faster initial load: HTML arrives with data already populated
  • More secure: Better protection against XSS attacks
  • Scalable: Easy to add new pages without major code changes
  • Works without JS: Basic functionality available even if JS fails

Disadvantages

  • Slower navigation: Each page change requires full server round-trip
  • Tightly coupled: Frontend and backend code are strongly coupled
  • Server load: Server must generate HTML for every request
  • Less interactive: Full page reloads break user flow
  • TTFB issues: Time to First Byte can be slow on complex pages

🎯 Best For:

Applications requiring SEO (blogs, e-commerce, marketing sites), public content, first-time visitors who need fast initial load, and content-heavy sites.

Static Site Generation (SSG)

Pre-rendered at Build Time - HTML pages are generated during the build process and served as static files.

How SSG Works

1
Build time: Generate all HTML pages
2
Deploy static HTML files to CDN
3
User requests page
4
CDN serves pre-built HTML instantly
5
Page renders immediately (no server processing)

Key Point: HTML generated once at build time, served instantly from CDN

Advantages

  • Fastest performance: Pre-built HTML served from CDN
  • Excellent SEO: Fully rendered HTML with all content
  • Low server costs: No server processing needed
  • High availability: CDN handles traffic spikes easily
  • Security: No server-side vulnerabilities

Disadvantages

  • Build time: Must rebuild for any content changes
  • Not for dynamic content: Can't handle user-specific or real-time data
  • Long build times: Large sites can take hours to build
  • No personalization: Same HTML for all users
  • Deployment delay: Changes require rebuild and redeploy

🎯 Best For:

Blogs, documentation sites, marketing pages, portfolios, and any site with mostly static content that doesn't change frequently. Perfect for JAMstack applications.

Incremental Static Regeneration (ISR)

SSG with Periodic Updates - Pages are statically generated at build time, but can be regenerated on-demand or on a schedule.

How ISR Works

1
Build time: Generate initial HTML pages
2
Deploy static HTML to CDN
3
User requests page → CDN serves cached HTML
4
After revalidate time (e.g., 60s), regenerate in background
5
Next request gets fresh HTML

Key Point: Best of both worlds - static performance with dynamic updates

Advantages

  • Fast performance: Static pages served from CDN
  • Fresh content: Pages regenerate automatically
  • Scalable: No server load for cached pages
  • On-demand revalidation: Update specific pages instantly
  • Great SEO: Pre-rendered HTML with up-to-date content

Disadvantages

  • Stale content: Users may see old content until regeneration
  • Complexity: More complex than pure SSG
  • Build time: Still need initial build
  • Platform dependent: Requires specific hosting (e.g., Vercel, Netlify)
  • Cache invalidation: Need to manage revalidation strategy

🎯 Best For:

E-commerce product pages, blog posts, documentation that updates occasionally, and sites that need static performance but with periodic content updates. Perfect for content that changes but not in real-time.

ISR Revalidation Strategies:

  • Time-based: Regenerate every X seconds (e.g., 60s)
  • On-demand: Trigger regeneration via API/webhook
  • Hybrid: Combine both approaches

Comparison Table

AspectCSRSSRSSGISR
Initial Load⚠ Slower - Must load JS first✓ Fast - HTML with data ready✓ Fastest - Pre-built HTML✓ Fastest - Pre-built HTML
Subsequent Navigation✓ Fastest - Only data fetched✗ Slower - Full page reload✓ Fast - Static files✓ Fast - Static files
SEO✗ Poor - JS-rendered content✓ Excellent - Pre-rendered HTML✓ Excellent - Pre-rendered HTML✓ Excellent - Pre-rendered HTML
Content Updates✓ Instant - Client-side✓ Instant - Server-side✗ Requires rebuild - Build time⚠ Periodic - Revalidation
Server Load✓ Low - Static files only✗ High - Every request✓ None - CDN only✓ Low - Only on revalidation
Build Time✓ Fast - No pre-rendering✓ Fast - No pre-rendering✗ Slow - All pages at build⚠ Medium - Initial build
Dynamic Content✓ Full support✓ Full support✗ Limited - Static only⚠ Periodic updates

Decision Guide

Choose CSR when:

  • Building highly interactive apps (dashboards, admin panels)
  • SEO is not critical (authenticated apps, internal tools)
  • You need rich client-side interactions and real-time updates
  • Content is highly personalized per user

Choose SSR when:

  • SEO is critical (blogs, e-commerce, marketing sites)
  • Content changes frequently and needs to be fresh
  • You need user-specific content but want SEO benefits
  • First-time visitor experience is important

Choose SSG when:

  • Content is mostly static (blogs, documentation, portfolios)
  • You want the best possible performance
  • You want to minimize server costs
  • Content doesn't change frequently

Choose ISR when:

  • You want SSG performance but need periodic updates
  • Content changes but not in real-time (e-commerce products, blog posts)
  • You have thousands of pages but only some update frequently
  • You want to balance performance with content freshness

Hybrid Approaches: Combining CSR and SSR

Modern applications often combine CSR and SSR to get the best of both worlds: fast initial load with SEO benefits from SSR, and smooth client-side navigation from CSR.

The Hybrid Model: SSR + CSR Hydration

How it works: Server renders HTML with data, then JavaScript "hydrates" the page to enable client-side navigation.

The Hydration Process

1
Server renders HTML with initial data
  • HTML arrives fully populated
  • Search engines can crawl content
  • Users see content immediately
2
JavaScript bundle loads in background
  • React/Next.js JavaScript downloads
  • Framework initializes
3
Hydration occurs
  • React attaches event handlers to server-rendered HTML
  • Page becomes interactive
  • Client-side router takes over
4
Subsequent navigations use CSR
  • Only data fetched (no full page reload)
  • Smooth transitions
  • Fast navigation experience

Key Benefit: Best of both worlds - SEO-friendly initial load + fast client-side navigation

Implementation Patterns

1. Next.js Pages Router (getServerSideProps + Client Navigation)

// pages/products/[id].js
// Initial page load: SSR
export async function getServerSideProps({ params }) {
  const product = await fetchProduct(params.id);
  return { props: { product } };
}

export default function ProductPage({ product }) {
  const router = useRouter();
  
  // After hydration, Next.js router handles navigation
  // Subsequent navigations use CSR (client-side routing)
  return (
    <div>
      <h1>{product.name}</h1>
      <Link href="/products/123">Next Product</Link>
      {/* This link uses CSR after initial load */}
    </div>
  );
}

What happens: First visit: Server renders HTML → Fast initial load + SEO. Click link: Client-side navigation → Only data fetched → Fast navigation.

2. Next.js App Router (Server Components + Client Components)

// app/products/[id]/page.tsx
// Server Component - Renders on server
async function ProductPage({ params }) {
  const product = await fetchProduct(params.id);
  
  return (
    <div>
      <ProductDetails product={product} />
      <InteractiveButton /> {/* Client Component */}
    </div>
  );
}

// app/products/[id]/components/InteractiveButton.tsx
'use client'; // Client Component - Hydrates on client
export function InteractiveButton() {
  const [count, setCount] = useState(0);
  // This component hydrates on client for interactivity
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

What happens: Server Components: Render on server → No JavaScript sent → Better performance. Client Components: Hydrate on client → Enable interactivity. Navigation: Uses CSR for fast transitions.

3. Streaming SSR with Selective Hydration

// app/dashboard/page.tsx
import { Suspense } from 'react';

export default function Dashboard() {
  return (
    <div>
      {/* Critical content streams first */}
      <Header />
      
      {/* Non-critical content loads progressively */}
      <Suspense fallback={<Skeleton />}>
        <UserStats /> {/* Server Component */}
      </Suspense>
      
      {/* Interactive parts hydrate separately */}
      <InteractiveChart /> {/* Client Component */}
    </div>
  );
}

Benefits: Critical content renders immediately. Non-critical content streams in. Interactive parts hydrate independently. Better perceived performance.

4. Partial Hydration (Islands Architecture)

// Only hydrate specific interactive components
function BlogPost({ post }) {
  return (
    <article>
      {/* Static content - no hydration needed */}
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
      
      {/* Only this component hydrates */}
      <CommentSection postId={post.id} />
    </article>
  );
}

// CommentSection.tsx
'use client';
export function CommentSection({ postId }) {
  // Only this component sends JavaScript to client
  const [comments, setComments] = useState([]);
  // Rest of page stays static
}

Benefits: Minimal JavaScript sent to client. Faster initial load. Only interactive parts hydrate. Better performance on low-end devices.

Real-World Examples

E-commerce Product Page

// SSR for SEO + CSR for navigation
export async function getServerSideProps({ params }) {
  const product = await fetchProduct(params.id);
  const relatedProducts = await fetchRelatedProducts(params.id);
  
  return { props: { product, relatedProducts } };
}

export default function ProductPage({ product, relatedProducts }) {
  return (
    <div>
      {/* SSR content - SEO friendly */}
      <ProductInfo product={product} />
      
      {/* Client-side interactive features */}
      <AddToCartButton product={product} />
      <ProductCarousel products={relatedProducts} />
      
      {/* CSR navigation */}
      <Link href="/products/123">Related Product</Link>
    </div>
  );
}

Why hybrid: Product info: SSR for SEO (search engines can index). Add to cart: CSR for instant feedback. Navigation: CSR for smooth transitions.

Social Media Feed

// Initial feed: SSR, infinite scroll: CSR
export async function getServerSideProps() {
  const initialPosts = await fetchPosts({ limit: 10 });
  return { props: { initialPosts } };
}

export default function Feed({ initialPosts }) {
  const [posts, setPosts] = useState(initialPosts);
  
  const loadMore = async () => {
    // CSR for loading more posts
    const morePosts = await fetch('/api/posts?offset=10');
    setPosts([...posts, ...morePosts]);
  };
  
  return (
    <div>
      {/* SSR initial posts - SEO friendly */}
      {posts.map(post => <PostCard key={post.id} post={post} />)}
      
      {/* CSR for infinite scroll */}
      <button onClick={loadMore}>Load More</button>
    </div>
  );
}

Why hybrid: Initial posts: SSR for SEO and fast first paint. Load more: CSR for smooth infinite scroll. Best user experience + SEO benefits.

Performance Benefits

  • Fast initial load: Server-rendered HTML shows immediately
  • Fast navigation: Client-side routing after hydration
  • Progressive enhancement: Works even if JavaScript fails
  • Selective hydration: Only hydrate what's needed

SEO Benefits

  • Crawlable content: Search engines see full HTML
  • Meta tags: Proper Open Graph and Twitter cards
  • Social sharing: Rich previews work correctly

UX Benefits

  • No blank screen: Content visible immediately
  • Smooth transitions: Client-side navigation feels instant
  • Works offline: After initial load, app can work offline

When to Use Hybrid Approach

Use SSR + CSR hybrid when:

  • You need SEO but also want fast navigation
  • Initial page load is critical (e-commerce, blogs)
  • You have both static and dynamic content
  • You want progressive enhancement

Common patterns:

  • Public pages: SSR for SEO (homepage, product pages, blog posts)
  • App pages: CSR for speed (dashboard, admin, authenticated areas)
  • Mixed pages: SSR initial + CSR interactions (product page with reviews)

Other Hybrid Patterns

SSG + CSR

Use case: Static content with interactive features

Blog posts: SSG for performance. Comments section: CSR for real-time updates.

ISR + CSR

Use case: Periodically updated content with client interactions

Product pages: ISR for freshness. Shopping cart: CSR for instant updates.

SSR + SSG + CSR

Use case: Different strategies for different pages

Homepage: SSG (rarely changes). Product pages: ISR (periodic updates). Dashboard: CSR (authenticated, no SEO needed).

Best Practices

  1. Start with SSR for public pages - Get SEO benefits
  2. Add CSR for navigation - Use client-side routing after hydration
  3. Use selective hydration - Only hydrate interactive components
  4. Stream critical content - Use Suspense for progressive loading
  5. Monitor performance - Track TTFB, FCP, and hydration time

Recommendation: Most production apps use hybrid approaches. Start with one strategy, then add others where they make sense based on page requirements.