FNA Technology Header Logo
ServicesWorkAboutBlog
[ start a project ]
FNA Technology Footer Logo

Transforming your digital vision into reality. Software, AI, web & mobile — built for outcomes.

[email protected] footer link+91 8879510299 footer link
Share page:
MAIN
HomeOur ServicesProjectsCompany Blog
COMPANY
About UsContact UsLinkedIn
LEGAL
Privacy PolicyTerms & Conditions
© 2026 FNA TECHNOLOGY LLP — ALL RIGHTS RESERVEDIndia · UK · Middle East
SSG vs SSR vs ISR: Choose the Best Strategy (2026)Compare SSG vs SSR for web performance. Learn how static generation and server-side rendering impact Core Web Vitals, page speed, and SEO ranking.Business owners, developers, CTOsSSG vs SSR web performance, static site generation vs server side rendering, incremental static regeneration Next.js, partial prerendering Next.js 15, rendering strategy web development 2026, Next.js rendering modes, ISR vs SSR performanceFNA Technology
Web Development

SSG vs SSR vs ISR: Choose the Best Strategy (2026)

May 4, 2026
7 min read
FNA Technology
Web rendering strategy comparison diagram showing SSG, SSR, ISR and PPR data flow

The short version: SSG is fastest but only works for content known at build time. SSR is flexible but costs server compute per request. ISR is the pragmatic middle ground — static performance with scheduled freshness. Partial Prerendering (Next.js 15 stable) is the new option for pages that are mostly static with a few dynamic sections. Choosing wrong costs you either performance or stale content.

Most rendering strategy debates miss the actual question: what is the data freshness requirement for this specific page? Start there, and the right rendering mode usually becomes obvious.

The four rendering modes explained

Static Site Generation (SSG)

Pages are built once at deploy time. The HTML is stored on a CDN and served to every user without any server involvement.

Code
// app/blog/[slug]/page.tsx — Next.js 15 App Router
import { getBlogBySlug, getAllBlogSlugs } from '@/data/blogUtils';

// Pre-generate all blog slugs at build time
export async function generateStaticParams() {
  const slugs = await getAllBlogSlugs();
  return slugs.map(slug => ({ slug }));
}

// This page is fully static — built once, served from CDN
export default async function BlogPost({ params }: { params: { slug: string } }) {
  const blog = await getBlogBySlug(params.slug);
  return <article>{blog.content}</article>;
}

TTFB: 10–50ms (CDN cache hit) Content freshness: Only as fresh as the last build Infrastructure cost: Essentially zero per request Best for: Blog posts, documentation, marketing pages, anything where content doesn't change between deploys

Limitation: A 10,000-page site with daily content updates needs either very fast builds or ISR. Full static builds that take 20 minutes mean your published content is 20 minutes stale minimum.


Server-Side Rendering (SSR)

HTML is generated on the server for every request. The server fetches data, renders the page, and sends HTML to the browser.

Code
// app/dashboard/orders/page.tsx — SSR (dynamic, per-request)
import { cookies } from 'next/headers';
import { getOrdersForUser } from '@/services/orders';

// No generateStaticParams = dynamic SSR by default in App Router
export default async function OrdersPage() {
  const sessionCookie = cookies().get('session')?.value;
  const userId = await validateSession(sessionCookie);

  // Fetches fresh data on every request — this is the point of SSR
  const orders = await getOrdersForUser(userId);

  return (
    <div>
      {orders.map(order => <OrderCard key={order.id} order={order} />)}
    </div>
  );
}

TTFB: 100–500ms+ (server must fetch data and render before responding) Content freshness: Always current — fetches fresh data per request Infrastructure cost: Server compute per request; scales with traffic Best for: User-specific pages (dashboards, account pages), real-time data, anything requiring session/auth data per request

Limitation: Every request hits the server. Under high traffic, SSR requires horizontal scaling. Slow database queries directly delay the user's page load.


Incremental Static Regeneration (ISR)

Pages are pre-built like SSG but automatically revalidated after a set time window. The first request after the revalidation window triggers a background rebuild; the stale page is served to that user while the fresh version is generated.

Code
// app/products/[id]/page.tsx — ISR with 1-hour revalidation
export const revalidate = 3600; // seconds

export async function generateStaticParams() {
  const products = await getTopProducts(1000); // pre-build top 1000 products
  return products.map(p => ({ id: p.id }));
}

export default async function ProductPage({ params }: { params: { id: string } }) {
  const product = await getProduct(params.id);
  return <ProductDetail product={product} />;
}

TTFB: 10–50ms for cached pages (CDN hit); first request after revalidation window is served stale while fresh version rebuilds in background Content freshness: Within the revalidation window (1 hour in the example above) Infrastructure cost: Low — only one rebuild per revalidation window regardless of traffic volume Best for: Product pages, news articles, blog indexes, any content that changes on a predictable schedule and where N-minutes-stale is acceptable

On-demand revalidation — trigger a rebuild immediately when content changes, rather than waiting for the time window:

Code
// app/api/revalidate/route.ts
import { revalidatePath, revalidateTag } from 'next/cache';
import { NextRequest } from 'next/server';

export async function POST(request: NextRequest) {
  const secret = request.headers.get('x-revalidate-secret');

  if (secret !== process.env.REVALIDATE_SECRET) {
    return Response.json({ error: 'Unauthorized' }, { status: 401 });
  }

  const { path, tag } = await request.json();

  if (path) revalidatePath(path);       // revalidate specific path
  if (tag) revalidateTag(tag);          // revalidate all pages tagged with this

  return Response.json({ revalidated: true });
}

Call this endpoint from your CMS webhook when content is published. The CDN cache clears immediately.


Partial Prerendering (PPR) — Next.js 15 stable

PPR lets a single page have a static shell (served instantly from CDN) and dynamic sections (streamed in after the shell loads). No choosing between SSG and SSR for the whole route.

Code
// app/product/[id]/page.tsx — PPR: static shell + dynamic sections
import { Suspense } from 'react';
import { ProductInfo } from '@/components/ProductInfo';         // static
import { StockStatus } from '@/components/StockStatus';         // dynamic — real-time
import { PersonalisedRecs } from '@/components/PersonalisedRecs'; // dynamic — user-specific

export default async function ProductPage({ params }: { params: { id: string } }) {
  const product = await getProduct(params.id); // fetched at build time (static)

  return (
    <>
      {/* Served from CDN instantly */}
      <ProductInfo product={product} />

      {/* Streamed in after shell loads — doesn't block initial render */}
      <Suspense fallback={<StockSkeleton />}>
        <StockStatus productId={params.id} />
      </Suspense>

      <Suspense fallback={<RecsSkeleton />}>
        <PersonalisedRecs userId={getUserId()} />
      </Suspense>
    </>
  );
}

Enable PPR in next.config.ts:

Code
const nextConfig = {
  experimental: {
    ppr: true, // stable in Next.js 15
  },
};

TTFB: 10–50ms for the static shell (CDN); dynamic sections stream in 100–500ms later Content freshness: Static sections as fresh as the build; dynamic sections always current Best for: E-commerce product pages, landing pages with personalisation, any page that's mostly static but has a few real-time or user-specific sections


Decision matrix

Page typeRecommended modeWhy
Blog post, docs pageSSGContent known at build time, no per-user data
Product listing (large catalogue)ISR (1–24hr revalidation)Mostly static, prices/stock update periodically
Product page with real-time stockPPRStatic description + dynamic stock/recs
User dashboardSSRAlways per-user, always current
Shopping cartSSRSession data required, must be current
Marketing landing pageSSGZero dynamic content, maximum CDN performance
News articleISR (15–60 min)Mostly static, occasional updates
Search resultsSSRQuery-dependent, cannot pre-build
Admin panelSSRAuth-gated, user-specific, real-time

Performance benchmarks by rendering mode

MetricSSG (CDN hit)SSR (no cache)ISR (cache hit)PPR (shell)
TTFB10–50ms100–500ms10–50ms10–50ms
LCP targetUnder 1.5s1.5–3sUnder 1.5sUnder 1.5s
Infrastructure costNear zeroScales with trafficNear zeroNear zero
Content freshnessBuild timePer requestWithin revalidation windowMixed
SEO suitabilityExcellentExcellentExcellentExcellent

The mistake most teams make

Defaulting to SSR for everything because it's "safer" — it always has fresh data, so nothing can go wrong. This works until traffic scales. At 10,000 requests/minute, SSR for pages that haven't changed in months means you're paying server compute and adding latency to deliver HTML that could be served from CDN cache for a fraction of the cost.

My rule: start with SSG for everything. Add ISR where content updates on a schedule. Add SSR only for pages that genuinely need per-request, per-user data. Use PPR for the in-between cases.

For teams building on Next.js 15 specifically, the Next.js modern web development guide covers the App Router caching model in depth — understanding how fetch caching interacts with these rendering modes is necessary to avoid stale data bugs when mixing SSG and SSR on the same project.

Frequently Asked Questions

For Time to First Byte (TTFB), yes — SSG pages are served from CDN cache with no server processing, typically in under 50ms. SSR pages require server computation before responding, adding 50–500ms depending on what the server does. But SSG's speed advantage disappears if the CDN cache is cold (first request after a build or cache expiry still hits the origin), and SSR with aggressive edge caching can approach SSG performance for popular routes.

Use ISR when your content changes on a predictable schedule and occasional stale data is acceptable. A product page that updates its price hourly is a good ISR candidate — set revalidate: 3600 and accept that some users see an hour-old price rather than paying SSR costs on every request. Use SSR when data must be current per-request: dashboards, shopping carts, anything that reads user-specific session data.

No. SSG is often the best choice for SEO because search engines receive fully rendered HTML without JavaScript execution. The SEO risk with SSG is stale content — if a page isn't rebuilt after a significant update, Google indexes the old version. ISR mitigates this by automatically revalidating pages on a schedule. For frequently updated content, SSR or ISR is more appropriate than a full static build.

Partial Prerendering (PPR) is a Next.js 15 feature that allows a single page to have a statically generated shell served instantly from CDN, with dynamic sections streamed in via Suspense boundaries. It reached stable in Next.js 15 and is the best of both worlds for pages that are mostly static with a few dynamic sections — like a product page where the description is static but the stock status and personalized recommendations are dynamic.

LCP (Largest Contentful Paint) is most directly affected. SSG pages served from CDN typically achieve LCP under 1.5 seconds. SSR pages with no caching can hit 2.5–4 seconds LCP on slower servers or distant regions. TTFB is the upstream metric to watch — under 200ms is good, under 500ms is acceptable. For pages with client-side hydration, INP (Interaction to Next Paint) matters more than rendering mode — heavy JavaScript bundles cause poor INP regardless of how the initial HTML was generated.

#SSG vs SSR web performance#static site generation vs server side rendering#incremental static regeneration Next.js#partial prerendering Next.js 15#rendering strategy web development 2026#Next.js rendering modes#ISR vs SSR performance
Share this article:
FNA Technology

Written by

FNA Technology

Team Member at FNA Technology

FNA Technology is a software development company specializing in AI, mobile apps, and web solutions.

Work with us