· rendering / nextjs / astro

Static vs dynamic rendering in 2026: pick your mode

The SSG-vs-SSR binary is obsolete. Six rendering modes now cover the full spectrum — here is which one fits your use case, with benchmarks and code.

By

1,999 words · 10 min read

For most new web apps, use PPR with Cache Components in Next.js 16. For content-heavy sites without heavy React, use Astro Server Islands. Reserve Edge SSR on Cloudflare Workers for Astro projects and auth middleware — not for heavy Next.js SSR workloads, where it runs 3.55× slower than Vercel Fluid.

The “static vs dynamic” question is the wrong question. In 2026, you are choosing between six rendering modes. The right answer depends on your TTFB budget, data freshness requirements, and how much complexity you can afford to own.

Who this is for

Frontend and full-stack engineers picking a rendering strategy for a new app, or questioning whether to migrate an existing one. If you are building a CRUD admin panel that never faces Google, CSR is the answer and the rest of this article is not for you.

What this covers

Six rendering modes — SSG, ISR, Streaming SSR, PPR/Cache Components, Edge SSR on Cloudflare Workers, and Astro Server Islands — with their real TTFB profiles, caching characteristics, and the workloads where each one wins. Benchmarks come from primary sources: Vercel’s documented Fluid compute benchmark, SitePoint’s 2026 RSC streaming case study (paywalled), the Enterspeed 6-framework SSR benchmark, and the Web Almanac 2024 performance chapter. Version numbers: Next.js 16.2, Astro 5, Cloudflare Workers (May 2026).

The six rendering modes

1. SSG — static site generation

TTFB: ~20ms (CDN-cached)
Data freshness: Build-time only
Complexity: Low

Pages are built at deploy time and served from a CDN. No server involved on request. This is the best option for docs, marketing pages, and blogs where content changes daily or weekly.

The limitation is mechanical: you can only serve what you built. A 50,000-product catalog with real-time inventory cannot ship as SSG without accepting stale data.

2. ISR — incremental static regeneration

TTFB: ~20ms (CDN hit)
Data freshness: Instant on publish (with on-demand invalidation)
Complexity: Medium

ISR is SSG with a background revalidation hook. The preferred pattern in 2026 is on-demand tag revalidation via revalidateTag, not time-based intervals. When a product changes, your CMS webhook calls your revalidation endpoint; the CDN serves fresh content on the next request.

This is the e-commerce sweet spot: CDN TTFB on cached pages, near-instant freshness after publish. The main footgun is cache poisoning — if your revalidation webhook fires on draft saves rather than publish events, readers see unpublished content.

3. Streaming SSR

TTFB: 40–90ms first bytes
Data freshness: Real-time
Complexity: Medium

React 19 + Suspense sends the page shell immediately, then streams in dynamic sections as data resolves. In SitePoint’s 2026 RSC case study (paywalled — URL returns HTTP 403), this dropped TTFB from 450ms to 45ms and LCP from 1.2s to 380ms. The shell is fast; the rest follows.

The caching story is weaker than SSG or PPR. The shell is not CDN-cacheable the same way a fully static asset is — you still hit an origin on every request to open the stream. Good for social feeds and personalized dashboards; not worth the architecture for pages that are mostly static.

TTFB: 20–80ms (CDN shell, p75)
Data freshness: Shell indefinite; dynamic holes real-time
Complexity: Medium

Partial Pre-Rendering landed stable in Next.js 16 (released October 21, 2025). The experimental.ppr flag is gone. Opt in with cacheComponents: true in your next.config.ts. The use cache directive is stable in Next.js 16.2.

For the full upgrade story — including the caching-model flip that catches most teams off guard — see our Next.js 16 review.

PPR’s model: the page shell is pre-rendered and CDN-cached like SSG, while dynamic holes inside <Suspense> boundaries stream in real-time from the origin. The shell delivers CDN-cached TTFB — the same speed profile as SSG — while dynamic sections fetch fresh on every request. You get CDN speed on the majority of the page and real-time data where you need it.

Here is what it looks like at the component level:

// app/product/[id]/page.tsx — Next.js 16.2+
import { Suspense } from 'react'
import { ProductDetails } from './ProductDetails'
import { LiveInventory } from './LiveInventory'

// This component renders as a static CDN-cached shell
export default function ProductPage({ params }: { params: { id: string } }) {
  return (
    <main>
      <ProductDetails id={params.id} />
      {/* This boundary streams from origin at request time */}
      <Suspense fallback={<div>Loading inventory…</div>}>
        <LiveInventory id={params.id} />
      </Suspense>
    </main>
  )
}
// ProductDetails.tsx — eligible for CDN caching
'use cache'

export async function ProductDetails({ id }: { id: string }) {
  const res = await fetch(`/api/products/${id}`)
  const data = await res.json()
  return <h1>{data.name}</h1>
}
// LiveInventory.tsx — real-time, bypasses CDN cache

export async function LiveInventory({ id }: { id: string }) {
  const res = await fetch(`/api/inventory/${id}`, { cache: 'no-store' })
  const { available, eta } = await res.json()
  return <p>{available} in stock — ships {eta}</p>
}

The 'use cache' directive on ProductDetails tells Next.js this component can be pre-rendered and served from the CDN indefinitely. LiveInventory opts out and hits the origin on every request. Both components share the same page, the same URL, and the same fast CDN shell.

If you are starting a new Next.js app in 2026, this is the baseline.

5. Edge SSR — Cloudflare Workers

TTFB: 8–25ms (nearest PoP)
Data freshness: Real-time
Complexity: High

Cloudflare Workers distributes your server across 300+ points of presence with sub-1ms cold starts. For users globally, you can hit 8–25ms TTFB — faster than what most origin-server setups achieve for dynamic content.

There is a documented catch: Edge SSR is not a universal win for heavy Next.js SSR. In Vercel’s 100-iteration benchmark, Next.js SSR on Cloudflare Workers clocked 1.895s vs 0.534s on Vercel Fluid — 3.55× slower. Workers’ V8 isolate runtime imposes real costs on memory-intensive Next.js renders. The Web Almanac 2024 also flags the context: server-rendered pages achieve ~60% “good LCP” scores vs ~45% for CSR pages, but that gap narrows when you compare optimized edge deployments with comparable infrastructure.

The actual sweet spots for Cloudflare Workers:

  • Astro projects with lightweight templates
  • Auth middleware and cookie inspection at the edge
  • A/B testing and traffic splitting at the PoP level
  • Cloudflare-native stacks using D1, KV, and R2

For a detailed cost and memory comparison between Workers and Vercel Functions, see Cloudflare Workers vs Vercel Functions.

A minimal Worker looks like this:

// worker.js — serving region-specific content from KV
export default {
  async fetch(request, env) {
    const country = request.cf?.country ?? 'US'

    const content =
      (await env.CONTENT_KV.get(`landing:${country}`)) ??
      (await env.CONTENT_KV.get('landing:US'))

    return new Response(content, {
      headers: { 'Content-Type': 'text/html;charset=UTF-8' },
    })
  },
}

Workers shine here because the KV lookup is local to the PoP. No round-trip to an origin. The heavy-Next.js warning does not apply when the rendering logic is this lightweight.

Do not reach for Workers because “edge = fast.” Reach for it when you specifically need global distribution with a lightweight runtime.

6. Astro Server Islands

TTFB: ~20ms (CDN shell)
Data freshness: Per-island, on demand
Complexity: Medium

Astro 5 (December 2024) made Server Islands stable. The model: a fully static CDN-served page with opt-in server:defer components that render from the server on request. No React runtime cost for the static majority. The Enterspeed benchmark placed Astro at 0.8s LCP — competitive with SSG — while supporting surgical per-request personalization. If you are deciding between Astro and Next.js at the framework level, Next.js vs Astro 2026 covers when the static-site advantage is decisive.

---
// src/pages/product/[id].astro
import ProductHero from '../components/ProductHero.astro'
import UserRecommendations from '../components/UserRecommendations.astro'

const { id } = Astro.params
---

<html>
  <body>
    <!-- Static: pre-built, served from CDN, zero JS weight -->
    <ProductHero {id} />

    <!-- Server Island: renders from origin on request -->
    <UserRecommendations {id} server:defer>
      <div slot="fallback">Loading recommendations…</div>
    </UserRecommendations>
  </body>
</html>

UserRecommendations streams in after the CDN-served shell. The rest of the page has already painted. If you add React-based interactivity to an island, you pay the React bundle cost only for that island — not for the whole page.

Best fit: content sites (media, docs, marketing) where most of the page is genuinely static but you need per-user sections such as logged-in state, recommendations, or cart counts.

Decision matrix

ModeTTFBCacheabilityData freshnessComplexityBest for
SSG~20ms (CDN)★★★★★Build-timeLowDocs, marketing, blogs
ISR (on-demand)~20ms (CDN hit)★★★★★Instant on publishMediumE-commerce, CMS-driven
Streaming SSR40–90ms first bytes★★ (shell only)Real-timeMediumSocial feeds, dashboards
PPR / Cache Components20–80ms (CDN shell)★★★★Shell: ∞ / Holes: real-timeMediumModern default
Edge SSR (CF Workers)8–25ms (PoP)★★★ (PoP-local)Real-timeHighGlobal Astro apps, auth middleware
Server Islands (Astro 5)~20ms (CDN shell)★★★★★Per-island on demandMediumContent sites + personalization
CSR~50ms (app shell)★★★ (app shell)Real-timeLow–MediumAdmin panels, internal tools

Verdict

New Next.js app: Default to PPR with Cache Components. Set cacheComponents: true, mark slow or personalized components with 'use cache' vs { cache: 'no-store' }, wrap dynamic holes in <Suspense>. You get CDN TTFB on the shell and real-time data where you need it.

E-commerce catalog at scale: ISR with on-demand revalidateTag invalidation. The CDN serves the fast cached version; your CMS webhook invalidates on publish. You get CDN-level TTFB without rebuilding 50,000 pages per content change.

Content-heavy site, no heavy React: Astro Server Islands. Pay no React runtime cost for static content. Pay it only for islands that need interactivity or personalization.

Global edge distribution: Cloudflare Workers for Astro or lightweight templates. Not for heavy Next.js SSR — the 3.55× performance gap is documented and has not been disputed.

Admin panels and internal dashboards: CSR. SEO is not a factor, data is inherently user-specific, the app shell caches fine.

Pick SSG if your content is small and stable. Pick ISR when your catalog is large and your CMS pushes on publish. Pick Streaming SSR when your page is dominated by personalized real-time data with no useful static shell. Pick PPR for everything in between — that is most apps.

The old binary was a useful shorthand in 2021. In 2026, PPR is the practical convergence of static speed and real-time data. Start there, pull back to a simpler mode if the complexity is not justified.

Caveats

ISR at large catalog scale (100K+ pages with aggressive tag invalidation) was not benchmarked by toolchew — the pattern described here is documented Next.js behavior and Vercel’s published guidance, not a number toolchew measured.

The streaming SSR case study figures (TTFB 450ms → 45ms, LCP 1.2s → 380ms) come from SitePoint’s 2026 reporting, not a toolchew test. The SitePoint URL returns HTTP 403 and could not be independently verified — the figures are stated here with that caveat and the source is noted as paywalled inline.

The Vercel Fluid vs Cloudflare Workers benchmark (0.534s vs 1.895s) was run by Vercel, which has a commercial interest in Fluid looking good. The methodology is documented and the finding has not been credibly disputed externally, but treat it as one data point — not an independent audit.

Affiliate links: both Vercel and Cloudflare are recommended in this article on merit. Vercel for PPR and heavy Next.js SSR. Cloudflare for global edge with Astro. The verdict would not change if neither had an affiliate program.

References

  1. Next.js 16 release blog — October 21, 2025
  2. Next.js Caching docs v16.2.6 — May 2026
  3. Astro Server Islands docs (Astro 5)
  4. Vercel Fluid Compute benchmark
  5. Cloudflare Workers Cache API docs
  6. Web Almanac 2024 Performance
  7. Enterspeed: 6-framework SSR benchmark
  8. SitePoint: RSC Streaming Performance 2026 — paywalled