Skip to content

SSR vs SSG Performance — Server-Side Rendering vs Static Generation

DodaTech Updated 2026-06-23 8 min read

In this tutorial, you will learn how server-side rendering and static site generation affect performance, when to use each approach, and how to optimize both. SSR generates HTML on each request while SSG pre-builds HTML at deploy time. DodaTech uses SSG for documentation and SSR for the interactive DodaZIP dashboard, choosing each based on content characteristics.

What You Will Learn

  • How SSR and SSG differ in build time, runtime, and caching behavior
  • How to measure and optimize SSR response times
  • How to measure and optimize SSG page weight
  • How hybrid rendering combines the best of both approaches

Why It Matters

The rendering approach directly determines TTFB, FCP, and the overall user experience. Choosing the wrong strategy can add 2-3 seconds of latency. DodaTech migrated its documentation site from SSR to SSG and saw TTFB drop from 800ms to 50ms because pages were served directly from CDN edge without any server processing.

Real-World Use Case

DodaTech originally built its documentation site with SSR using Next.js. As the site grew to 2000 pages, build times became irrelevant for the static approach, but server costs for SSR remained high. The migration to SSG (Next.js static export + Cloudflare Pages) reduced cloud costs by 60 percent and median page load time by 75 percent.

Prerequisites

You should understand HTTP request-response flow and basic React or Next.js concepts. Familiarity with CDN Configuration is helpful.

Step-by-Step Tutorial

Step 1: Understand the Performance Trade-offs

Aspect SSR SSG
TTFB Higher (server processing) Very low (static file)
FCP Good (full HTML) Good (full HTML)
Caching Dynamic (limited) Aggressive (full page)
Cold start Server processing time None
Build time None Build time per deploy
Content freshness Always fresh Requires rebuild

SSR is best for personalized, dynamic content. SSG is best for public, infrequently changing content.

Step 2: Measure SSR Performance

SSR adds server processing time to TTFB. Profile the server-side rendering function to identify bottlenecks.

// Next.js SSR page with timing instrumentation
export async function getServerSideProps({ req, res }) {
  const start = Date.now();

  // Simulate data fetching
  const data = await fetch('https://api.dodatech.com/products').then(r => r.json());

  const duration = Date.now() - start;
  console.log(`SSR render time: ${duration}ms`);

  // Add timing header for monitoring
  res.setHeader('Server-Timing', `ssr;dur=${duration}`);

  return { props: { data } };
}

Expected output: The Server-Timing header ssr;dur=340 indicates 340ms of server processing time. If this exceeds 500ms, optimize the data fetching or caching.

Step 3: Optimize SSR with Incremental Rendering

Use streaming SSR and component-level caching to reduce server processing time.

// React 18 streaming SSR with Suspense boundaries
import { Suspense } from 'react';

function ProductPage({ productId }) {
  return (
    <div>
      <h1>Product Details</h1>
      <Suspense fallback={<div>Loading reviews...</div>}>
        <Reviews productId={productId} />
      </Suspense>
    </div>
  );
}

async function Reviews({ productId }) {
  const reviews = await fetch(`https://api.dodatech.com/reviews/${productId}`)
    .then(r => r.json());
  return reviewList(reviews);
}

Expected behavior: The page renders the product details immediately and streams the reviews section when ready. The user sees content faster even if the reviews query is slow.

Step 4: Measure SSG Performance

SSG pages are pre-built HTML files served directly from a CDN. Measure their performance with Lighthouse.

# Lighthouse audit for SSG page
npx lighthouse https://docs.dodatech.com/getting-started --output json | \
  python3 -c "import sys,json;d=json.load(sys.stdin);print(f\"FCP: {d['audits']['first-contentful-paint']['numericValue']}ms, LCP: {d['audits']['largest-contentful-paint']['numericValue']}ms\")"

Expected output: FCP: 320ms, LCP: 450ms. SSG pages typically have FCP under 500ms because the HTML is served immediately.

Step 5: Optimize SSG with Incremental Static Regeneration (ISR)

ISR updates static pages without a full rebuild by revalidating them in the background.

// Next.js ISR page
export async function getStaticProps() {
  const data = await fetch('https://api.dodatech.com/products').then(r => r.json());

  return {
    props: { data },
    revalidate: 300, // Revalidate every 5 minutes
  };
}

export async function getStaticPaths() {
  const products = await fetch('https://api.dodatech.com/products/ids').then(r => r.json());
  return {
    paths: products.map(p => ({ params: { id: p.id } })),
    fallback: 'blocking', // Generate on-demand for new content
  };
}

Expected behavior: The first visitor after a rebuild hits a static page. If the page is older than 5 minutes, the next visitor triggers a background regeneration while still seeing the stale page. Subsequent visitors see the fresh page.

Step 6: Implement Hybrid Rendering

Use SSR for dynamic routes and SSG for static routes within the same application.

// next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/docs/:path*',
        headers: [
          { key: 'Cache-Control', value: 'public, s-maxage=31536000, immutable' }
        ]
      },
      {
        source: '/dashboard/:path*',
        headers: [
          { key: 'Cache-Control', value: 'private, no-cache' }
        ]
      }
    ];
  }
};

Documentation pages (SSG) get aggressive caching. Dashboard pages (SSR) bypass cache entirely.

Step 7: Compare Cold Start vs Warm Start

SSR pages have different performance on first request (cold start) vs subsequent requests. Measure both.

# Measure cold SSR (first request after deployment)
curl -s -o /dev/null -w "Cold: %{time_starttransfer}s\n" https://app.dodatech.com/

# Measure warm SSR (subsequent request)
curl -s -o /dev/null -w "Warm: %{time_starttransfer}s\n" https://app.dodatech.com/

Expected output: Cold: 1.2s, Warm: 0.4s. The cold start is slower because the server needs to initialize the application.

Step 8: Make the Decision Matrix

Use this decision matrix to choose between SSR and SSG:

Content Type SSR SSG ISR
Marketing pages No Yes No
Product listing (public) No Yes Yes
Product details (personalized) Yes No No
User dashboard Yes No No
Blog posts No Yes Yes
Documentation No Yes No
function chooseRenderingStrategy(pageType, contentFrequency, personalization) {
  if (personalization) return 'SSR';
  if (contentFrequency === 'realtime') return 'SSR';
  if (contentFrequency === 'hourly') return 'ISR';
  return 'SSG';
}

Learning Path

flowchart LR
  A[Critical Rendering Path] --> B[SSR vs SSG Performance]
  B --> C[Cache Strategy]
  B --> D[Database Query Optimization]
  C --> E[Performance Testing]
  
  style B fill:#4f46e5,color:#fff
  style A fill:#6366f1,color:#fff
  style C fill:#6366f1,color:#fff

Common Errors

  1. Using SSR for public content: Public content that could be SSG wastes server resources and adds latency. If the content is the same for every user, it should be static.

  2. No caching on SSR pages: Even SSR pages should have CDN-level caching for anonymous users. Implement cache headers that match the staleness tolerance of the content.

  3. Rebuilding the entire site on every content change: With ISR, only the changed page needs regeneration. Full rebuilds are wasteful for frequently updated sites.

  4. Using fallback: true for ISR without a loading state: The fallback: true mode shows an empty page until the static generation completes. Use fallback: 'blocking' for SEO-critical pages.

  5. Measuring SSG performance without CDN: Testing SSG directly from the origin server misses the CDN caching benefit. Always test through the CDN URL.

  6. Not accounting for database connection warmup: SSR pages that connect to a database experience slow first requests due to Connection Pool warmup. Use connection pooling with pre-warming.

Practice Questions

  1. What is the main performance advantage of SSG over SSR?
  2. How does Incremental Static Regeneration (ISR) differ from full SSG?
  3. Why might SSR have different cold start vs warm start performance?
  4. What is streaming SSR and how does it improve perceived performance?
  5. When would you choose SSR over SSG despite SSG being faster?

Answers: 1. SSG serves pre-built HTML files directly from CDN edge with no server processing, resulting in much lower TTFB. 2. ISR regenerates individual pages in the background when they become stale, without requiring a full site rebuild. 3. Cold start requires application initialization, database connection establishment, and JIT Compilation that are cached for warm requests. 4. Streaming SSR sends HTML to the browser in chunks as soon as each part is ready, allowing the browser to render content progressively. 5. When content is personalized per user (dashboards, account pages), SSR is required because the content cannot be pre-built.

Challenge

Build a hybrid Next.js application with three page types: a documentation page using SSG with ISR (revalidate every hour), a product listing page using ISR with fallback blocking, and a user dashboard using SSR. Implement appropriate Cache-Control headers for each page type and measure the TTFB, FCP, and LCP difference between the three rendering strategies.

FAQ

Does SSG always have better TTFB than SSR?

Yes, because SSG pages are static files served directly from CDN edge without any server processing. SSR requires the server to generate HTML on each request, adding at least some processing time.

Can I use SSG with dynamic content?

SSG with client-side data fetching works for dynamic content. The page shell is static, and the dynamic content loads via JavaScript after page load. This gives fast initial paint with fresh data.

What is the build time impact of SSG for large sites?

For a 10,000 page site, SSG build time can be several minutes. Next.js ISR and on-demand ISR (Next.js 14+) reduce this by only building pages that have changed.

Does SSR work without JavaScript?

Yes, SSR sends fully rendered HTML to the browser. The page is fully visible and functional without JavaScript, though interactivity may require JS enhancement.

What approach does DodaTech use for its products?

DodaTech uses SSG with Cloudflare Pages for its documentation and marketing sites (highly cacheable public content) and SSR on Vercel for the DodaZIP web dashboard (personalized, authenticated content). ISR bridges the gap for product listing pages.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro