Skip to main content

Command Palette

Search for a command to run...

Introduction to Web Rendering Strategies

Updated
11 min read

Hey there, Coding Chefs!

Ever wondered why some websites load instantly while others take forever to show content? Or why Netflix feels so snappy while some e-commerce sites make you wait ages? The secret lies in rendering strategies - the different ways we can serve content to users.

Think of rendering strategies as different cooking methods.

You can serve a meal instantly (microwave), prepare it fresh when ordered (diners), or have it ready and waiting for order (like Chowdeck). Each approach has its place, and choosing the right one can make, mar or break your user experience.

Let's dive into the fascinating world of web rendering strategies and discover which one fits your next project!

1. Static Site Generation (SSG): The Buffet Approach

What it is: All your pages are pre-built at build time and served as static HTML files. It's like preparing all your meals in advance and keeping them ready to serve.

How it works:

// Next.js SSG example
export async function getStaticProps() {
  const posts = await fetchPosts();

  return {
    props: { posts },
    revalidate: 60 // Regenerate every 60 seconds
  };
}

export default function Blog({ posts }) {
  return (
    <div>
      {posts.map(post => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.excerpt}</p>
        </article>
      ))}
    </div>
  );
}

Tech Stack: Next.js, Gatsby, Hugo, Jekyll, Nuxt.js (static mode), Astro

Architecture:

Build Time:
[CMS/Data] → [Build Process] → [Static HTML/CSS/JS] → [CDN]

Request Time:
[User] → [CDN] → [Static Files] → [Instant Load]

Perfect for:

  • Blogs and documentation sites

  • Marketing websites

  • Portfolios

  • Product landing pages

  • Company websites

Live Examples:

  • Netflix's landing pages - Lightning fast marketing pages

  • GitHub Pages - Documentation and project sites

  • Vercel's website - Company marketing site

  • Stripe's documentation - Developer docs

Pros:

✅ Blazing fast loading times
✅ Great SEO out of the box
✅ Excellent caching capabilities
✅ Lower server costs
✅ High security (no server-side vulnerabilities)

Cons:
❌ Build times increase with content volume as we need to generate more contents at build time
❌ Not suitable for real-time data
❌ Requires rebuild for content updates (i.e you need to be trigger the build, so your pipeline has to be connected to your content delivery mechanism)
❌ Limited dynamic functionality


2. Incremental Static Regeneration (ISR): The Smart Buffet

What it is: Like SSG but with the ability to update specific pages after build time. Imagine a buffet that can refresh individual dishes without replacing the entire spread.

How it works:

// Next.js ISR example
export async function getStaticProps({ params }) {
  const product = await fetchProduct(params.id);

  return {
    props: { product },
    revalidate: 3600, // Revalidate every hour
  };
}

export async function getStaticPaths() {
  const popularProducts = await fetchPopularProducts();

  return {
    paths: popularProducts.map(p => ({ params: { id: p.id } })),
    fallback: 'blocking' // Generate other pages on-demand
  };
}

Tech Stack: Next.js, Nuxt.js 3

Architecture:

Build Time:
[CMS] → [Build Popular Pages] → [CDN]

Request Time:
[User] → [CDN] → [Check TTL] → [Fresh? Serve : Regenerate] → [User]

Perfect for:

  • E-commerce product pages

  • News websites

  • Social media platforms

  • Content-heavy sites with frequent updates

  • Large-scale blogs

Live Examples:

  • Hulu - Video content pages

  • TikTok's web version - User profile pages

  • Reddit - Popular post pages

  • Medium - Article pages

Pros:
✅ Best of both worlds (speed + freshness)
✅ Scales to millions of pages
✅ Automatic cache invalidation
✅ Great for SEO
✅ Reduced build times

Cons:
❌ More complex than pure SSG
❌ First visitor after cache expiry waits longer
❌ Requires careful cache strategy planning
❌ Platform-specific (mainly Next.js)


3. Server-Side Rendering (SSR): The Diner Kitchen

What it is: Pages are generated on the server for each request. Like cooking each meal fresh when a customer orders.

How it works:

// Next.js SSR example
export async function getServerSideProps(context) {
  const { req, res, query } = context;
  const userSession = await getSession(req);
  const personalizedData = await fetchUserData(userSession.userId);

  return {
    props: {
      user: userSession,
      data: personalizedData
    }
  };
}

export default function Dashboard({ user, data }) {
  return (
    <div>
      <h1>Welcome back, {user.name}!</h1>
      <UserDashboard data={data} />
    </div>
  );
}

Tech Stack: Next.js, Nuxt.js, SvelteKit, Remix, Express + React, PHP, Ruby on Rails

Architecture:

Request Time:
[User] → [Server] → [Database] → [Generate HTML] → [Send to User]
                ↓
          [Template Engine]

Perfect for:

  • User dashboards

  • Admin panels

  • Personalized content

  • Real-time data applications

  • Authentication-heavy apps

Live Examples:

  • Facebook - Personalized feeds

  • Twitter/X - Timeline pages

  • Gmail - Inbox views

  • Slack - Workspace interfaces

  • Shopify Admin - Merchant dashboards

Pros:
✅ Real-time data
✅ Personalized content
✅ Great SEO
✅ Full access to server resources
✅ Secure (sensitive logic stays on server)

Cons:
❌ Slower than static approaches
❌ Higher server costs
❌ Server load increases with traffic
❌ Requires robust infrastructure
❌ Time to First Byte (TTFB) can be high


4. Client-Side Rendering (CSR): The “Chowdeck” Kitchen

What it is: The server sends a minimal HTML shell, and JavaScript builds the page in the browser. Like giving customers ingredients and letting them cook. Essentially, the content/meal is waiting to be requested for.

How it works:

// React CSR example
import { useState, useEffect } from 'react';

function ProductList() {
  const [products, setProducts] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchProducts() {
      const response = await fetch('/api/products');
      const data = await response.json();
      setProducts(data);
      setLoading(false);
    }

    fetchProducts();
  }, []);

  if (loading) return <div>Loading...</div>;

  return (
    <div>
      {products.map(product => (
        <ProductCard key={product.id} product={product} />
      ))}
    </div>
  );
}

Tech Stack: React, Vue.js, Angular, Svelte (SPA mode), Vanilla JavaScript

Architecture:

Initial Load:
[User] → [Server] → [HTML Shell + JS Bundle] → [Browser] → [API Calls] → [Render]

Subsequent Navigation:
[User Click] → [Browser] → [API Call] → [Update DOM]

Perfect for:

  • Interactive web applications

  • Dashboards with real-time updates

  • Games and multimedia apps

  • Apps requiring complex user interactions

  • Internal tools and admin panels

Live Examples:

  • Figma - Design tool interface

  • Discord - Chat application

  • Spotify Web Player - Music streaming interface

  • Notion - Note-taking app

  • CodePen - Code editor

Pros:
✅ Rich user interactions
✅ Fast navigation after initial load
✅ Reduced server load
✅ Great for app-like experiences
✅ Offline capabilities possible

Cons:
❌ Poor SEO by default (SEO engines see nothing on the page as they don’t typically run javascript)
❌ Slow initial page load
❌ Blank page while JavaScript loads
❌ Bundle size impacts performance
❌ Requires JavaScript enabled


5. Partial Hydration: The Selective Activation

What it is: Only specific parts of the page become interactive, leaving static content as-is. Like having some dishes ready to serve and some prepared fresh on demand.

How it works:

// Astro partial hydration example
---
// This runs on the server
const staticData = await fetchStaticContent();
---

<html>
  <body>
    <!-- Static content -->
    <header>{staticData.title}</header>

    <!-- Only this component becomes interactive -->
    <SearchBox client:load />

    <!-- Static again -->
    <footer>{staticData.footer}</footer>
  </body>
</html>

// SearchBox.jsx - Only this becomes interactive
export default function SearchBox() {
  const [query, setQuery] = useState('');
  // Interactive logic here
}

Tech Stack: Astro, Fresh (Deno), Marko, Qwik

Architecture:

Server:
[Generate Static HTML] → [Mark Interactive Islands] → [Send to Browser]

Browser:
[Render Static] → [Hydrate Islands Only] → [Interactive Components]

Perfect for:

  • Content-heavy sites with interactive widgets

  • Blogs with interactive components

  • Marketing sites with forms/search

  • Documentation with live examples

  • E-commerce with interactive features

Live Examples:

  • Shopify's blog - Static content with interactive cart

  • Astro's documentation - Static docs with interactive search

  • The Guardian - Articles with interactive polls/widgets

Pros:
✅ Best performance for content sites
✅ SEO-friendly
✅ Minimal JavaScript
✅ Progressive enhancement
✅ Fast Core Web Vitals

Cons:
❌ Limited framework support
❌ Complex state management between islands
❌ Learning curve for new concepts
❌ Less suitable for app-like experiences


6. Streaming SSR: The Live Kitchen Show

What it is: The server sends HTML in chunks as it's generated, showing content progressively. Like a live cooking show where you see each ingredient added.

How it works:

// React 18 Streaming example
import { Suspense } from 'react';

function App() {
  return (
    <html>
      <body>
        {/* This renders immediately */}
        <header>My App</header>

        {/* This streams in when ready */}
        <Suspense fallback={<div>Loading posts...</div>}>
          <AsyncPosts />
        </Suspense>

        {/* This also streams in independently */}
        <Suspense fallback={<div>Loading sidebar...</div>}>
          <AsyncSidebar />
        </Suspense>
      </body>
    </html>
  );
}

async function AsyncPosts() {
  const posts = await fetchPosts(); // This can take time
  return <PostList posts={posts} />;
}

Tech Stack: Next.js 13+, Remix, SvelteKit, React 18+ with Streaming

Architecture:

Request:
[User] → [Server] → [Stream Header] → [Stream Component 1] → [Stream Component 2] → [Complete]
                      ↓                ↓                    ↓
                 [User sees]      [User sees]          [User sees]

Perfect for:

  • News websites

  • Social media feeds

  • E-commerce with multiple data sources

  • Content platforms

  • Real-time applications

Live Examples:

  • Instagram web - Stories and feed streaming

  • Amazon - Product recommendations stream in

  • YouTube - Comments load progressively

  • LinkedIn - Feed content streams

Pros:
✅ Perceived performance improvement
✅ Better Core Web Vitals
✅ SEO-friendly
✅ Progressive content loading
✅ Reduced Time to First Byte perception

Cons:
❌ Complex implementation
❌ Debugging challenges
❌ Requires modern frameworks
❌ Browser compatibility considerations


7. Edge-Side Rendering (ESR): The Distributed Kitchen

What it is: Rendering happens on edge servers close to users. Like having mini-kitchens in every neighborhood.

How it works:

// Vercel Edge Runtime example
export const config = {
  runtime: 'edge',
};

export default async function handler(request) {
  const url = new URL(request.url);
  const country = request.geo?.country || 'US';

  // Generate content based on user location
  const localizedContent = await generateContent(country);

  return new Response(
    `<html>
      <body>
        <h1>Welcome from ${country}!</h1>
        ${localizedContent}
      </body>
    </html>`,
    {
      headers: { 'content-type': 'text/html' },
    }
  );
}

Tech Stack: Vercel Edge Functions, Cloudflare Workers, Deno Deploy, AWS Lambda@Edge

Architecture:

[User in Tokyo] → [Tokyo Edge Server] → [Generate HTML] → [User]
[User in London] → [London Edge Server] → [Generate HTML] → [User]
[User in NYC] → [NYC Edge Server] → [Generate HTML] → [User]

Perfect for:

  • Global applications

  • Personalization based on location

  • A/B testing

  • Authentication middleware

  • Content localization

Live Examples:

  • Shopify - Store localization

  • Cloudflare's dashboard - Edge-rendered analytics

  • Vercel's analytics - Real-time data processing

Pros:
✅ Ultra-low latency
✅ Global scalability
✅ Reduced origin server load
✅ Geographic personalization
✅ Better performance worldwide

Cons:
❌ Limited runtime capabilities
❌ Cold start latency
❌ Vendor lock-in
❌ Debugging complexity
❌ Limited database access


Choosing the Right Strategy: The Decision Matrix

StrategyInitial LoadSEOReal-time DataScalabilityComplexity
SSG⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
ISR⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
SSR⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
CSR⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Partial Hydration⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Streaming⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
ESR⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐

Quick Decision Guide

Choose SSG when:

  • Content doesn't change frequently

  • SEO is crucial

  • You want maximum performance

  • Budget is limited

Choose ISR when:

  • You have thousands of pages

  • Content updates regularly but not real-time

  • You need both performance and freshness

  • You're using Next.js

Choose SSR when:

  • You need personalized content

  • Data changes frequently

  • SEO is important

  • You have server infrastructure

Choose CSR when:

  • Building an interactive app

  • SEO isn't a priority

  • You need rich user interactions

  • Real-time updates are crucial

Choose Partial Hydration when:

  • You have mostly static content

  • You need some interactivity

  • Performance is critical

  • You're okay with newer tech

Choose Streaming when:

  • You have multiple data sources

  • User experience is priority

  • You're using modern frameworks

  • Performance optimization is key

Choose ESR when:

  • You have global users

  • Latency is critical

  • You need geographic personalization

  • You have edge infrastructure

Hybrid Approaches: The Best of All Worlds

Many modern applications combine multiple strategies:

// Next.js App Router example combining strategies
app/
├── page.js              // SSG for homepage
├── blog/
│   └── [slug]/
│       └── page.js      // ISR for blog posts
├── dashboard/
│   └── page.js          // SSR for user dashboard
└── app/
    └── page.js          // CSR for interactive app

Performance Tips

  1. Measure First: Use tools like Lighthouse, WebPageTest, and Core Web Vitals

  2. Progressive Enhancement: Start with SSG/SSR, add interactivity progressively

  3. Code Splitting: Only load JavaScript when needed

  4. Caching Strategy: Use CDNs, browser cache, and server-side caching effectively

  5. Monitor Real Users: Use RUM (Real User Monitoring) tools

Wrapping Up

Choosing the right rendering strategy is like choosing the right tool for the job. A hammer is great for nails but terrible for screws. Each rendering approach has its sweet spot:

  • Static sites → SSG/ISR

  • Apps with real-time data → SSR/CSR

  • Content + some interactivity → Partial Hydration

  • Global performance → Edge rendering

Remember: You don't have to pick just one! Modern applications often mix multiple strategies to get the best performance for each use case.

The key is understanding your users' needs, your content patterns, and your team's capabilities. Start simple, measure performance, and optimize based on real data.

Happy rendering, Coding Chefs! 🚀
A new day, another opportunity to build something secure and world-class! 🚀

More from this blog

C

Cracked Chefs by Oluwaferanmi Adeniji

19 posts

Battle-tested Coding patterns, Javascript wizardry, System Design, Product Engineering and Management, and architectural secrets.