Home › Modern Web › CDN Next.js Deployment
Modern Web

CDN for Next.js: ISR, SSG, and Edge Runtime Deployment Strategies

By Michael Chen, Network Security Engineer · September 1, 2026 · 9 min read

Next.js is not just a framework; it is a distributed rendering system. To unlock its performance, you must align its rendering modes — Static Generation, Incremental Static Regeneration, and Edge Runtime — with a modern CDN architecture.

Deploying Next.js without a CDN-aware strategy is leaving 70% of its performance on the table. Unlike a traditional single-page application, Next.js produces multiple output types that each demand a different caching and compute model at the edge. A static page generated at build time should be cached immutably for a year. An ISR page needs stale-while-revalidate semantics. An Edge Function must execute within 50ms of the user. If your CDN treats them all as generic origin responses, you get cache thrashing, slow TTFB, and unnecessary origin load.

This guide breaks down how to architect your CDN for each Next.js paradigm. We will cover cache-control headers, surrogate keys, revalidation flows, and when to push logic to the edge versus keeping it at the origin. The goal is sub-100ms global TTFB with minimal origin hits and zero stale-data surprises.

1. The Three Rendering Pillars: Where Compute Meets Cache

Every Next.js route resolves to one of four behaviors, and your CDN must distinguish them. Understanding this mapping is foundational to any CDN fundamentals guide for modern frameworks.

Static Site Generation (SSG): app/page.tsx without dynamic data or with generateStaticParams. Rendered once at build time to static HTML and JSON. Ideal for marketing pages, docs, and product listings. The CDN can cache these forever because the asset hash changes on redeploy.

Server-Side Rendering (SSR): Dynamic routes using cookies(), headers(), or searchParams without caching. Rendered per request at the origin. The CDN should typically bypass cache or use very short, private caching unless you add fetch with cache options.

Incremental Static Regeneration (ISR): The hybrid. Static generation with a time-based or on-demand revalidation window. The first request caches the page at the edge; subsequent requests are instant. After revalidate seconds, the next request triggers a background rebuild. This is where most CDN misconfigurations happen.

Edge Runtime: Code that runs on V8 isolates at the CDN edge, not in a Node.js server. Declared via export const runtime = 'edge'. Used for Middleware, Edge API Routes, and edge-rendered pages. It has constraints — no native Node APIs, 1-4MB code limit, 30s CPU limit — but offers single-digit millisecond execution near the user.

Security Note: Edge Functions execute outside your VPC. Never embed secrets or perform privileged database writes directly in Edge Runtime without a secure token exchange and origin validation. Validate all edge requests with signed headers.
Next.js CDN Architecture: SSG, ISR, and Edge Runtime Flow Diagram showing user request flowing through CDN edge to different Next.js rendering handlers. NEXT.JS CDN EDGE ARCHITECTURE ◉ BROWSER Anycast Request HTTPS/QUIC CDN EDGE POP Cache + Compute 150+ Global Locations SSG Immutable Cache max-age=31536000 ISR SWR Cache stale-while-revalidate EDGE V8 Isolate Middleware & Functions ORIGIN Node Server / Serverless Revalidation & SSR miss only CACHE BEHAVIOR HIT (edge) REVALIDATE COMPUTE (edge) FETCH origin
Figure 1: Request routing at the CDN edge. SSG is served immutably, ISR uses stale-while-revalidate, and Edge Runtime executes without origin fetch.

2. SSG + CDN: Set It and Forget It (Almost)

SSG is the simplest to cache and the easiest to break. When you run next build, Next.js emits HTML, RSC payloads, and static assets with content hashes. These files never change until the next deployment. Your CDN should treat them as immutable.

Performance Comparison: Edge vs Origin Processing
Metric Edge Processing Origin Processing Improvement
Latency (p50)8–15 ms120–300 ms15–20x faster
Cache Hit Ratio85–95%N/AReduces origin load
TLS Handshake1–5 ms (nearby PoP)50–150 ms10–30x faster
Bandwidth Cost$0.01–0.04/GB$0.05–0.12/GB3–5x cheaper
Availability99.99% (multi-PoP)99.9% (single DC)10x fewer outages

The optimal header strategy separates browser cache from CDN cache. Browsers can cache for a year, but the CDN needs deployment-aware invalidation. Use the CDN-Cache-Control draft header to give the edge a different TTL than the browser, a technique detailed in our CDN caching strategies deep dive.

// next.config.js — immutable asset headers for SSG
async headers() {
  return [
    {
      source: "/_next/static/:path*",
      headers: [
        { key: "Cache-Control", value: "public, max-age=31536000, immutable" },
        { key: "CDN-Cache-Control", value: "public, max-age=31536000, immutable" }
      ]
    },
    {
      source: "/:path*",
      // HTML pages — let ISR/SSG control via fetch cache
      headers: [{ key: "X-Content-Type-Options", value: "nosniff" }]
    }
  ];
}

On platforms like Vercel, Cloudflare, or Netlify, SSG pages are automatically uploaded to edge storage and served via Anycast. On a custom CDN (CloudFront, Fastly, Akamai), you must configure origin shielding and ensure your build output is synced to edge storage or that your origin returns Cache-Control: public, s-maxage=31536000, stale-while-revalidate for prerendered HTML. Avoid setting no-cache globally — it disables the entire benefit of SSG.

For cache invalidation, SSG requires atomic deploys. Do not purge by URL. Purge by deployment ID or use versioned URLs. Modern CDNs support surrogate keys: tag all assets from deployment d_abc123 and purge that key on rollback. This prevents mixed-version states where HTML references an old JS chunk.

3. ISR: The CDN’s Most Powerful — and Misunderstood — Feature

ISR is stale-while-revalidate at the framework level. It solves the core tension between static performance and dynamic content. Without a CDN that understands ISR, you will see either stale data forever or origin overload.

Here is the precise flow: A user requests /blog/[slug]. The CDN edge checks its cache. On a MISS, it fetches from origin, which renders the page, stores it in the Data Cache, and returns it with Cache-Control: s-maxage=60, stale-while-revalidate=300. The edge caches it. For the next 60 seconds, every request is a HIT. At 61 seconds, the cache is stale. The next request still gets the stale page instantly, but the edge triggers a background revalidation fetch to the origin. Once the origin finishes, the edge swaps the cache atomically. No user waits for regeneration.

// app/blog/[slug]/page.tsx — time-based ISR
export const revalidate = 60; // seconds

export async function generateStaticParams() {
  const posts = await fetch("https://api.example.com/posts").then(r => r.json());
  return posts.map((p) => ({ slug: p.slug }));
}

export default async function Page({ params }) {
  const data = await fetch(`https://api.example.com/posts/${params.slug}`, {
    next: { tags: [`post-${params.slug}`] }
  });
  return <Article data={data} />;
}

Time-based revalidation is good for low-stakes content. For CMS-driven sites, on-demand revalidation is superior. It gives you precise control and is critical for correct CDN cache invalidation. Instead of waiting 60 seconds, your CMS webhook calls revalidateTag('post-hello-world'), which purges both the Next.js Data Cache and the associated CDN cache entries via cache tags.

// app/api/revalidate/route.ts — on-demand ISR
import { revalidateTag } from "next/cache";
import { NextRequest, NextResponse } from "next/server";

export async function POST(req: NextRequest) {
  const { tag, secret } = await req.json();
  if (secret !== process.env.REVALIDATE_SECRET)
    return NextResponse.json({ error: "Invalid" }, { status: 401 });
  revalidateTag(tag);
  return NextResponse.json({ revalidated: true, tag });
}

Key CDN requirement: Your provider must support cache tagging or surrogate keys. Vercel does this natively via x-vercel-cache-tags. On Cloudflare, use Cache-Tag headers. On Fastly, use Surrogate-Key. Without tagging, on-demand ISR degrades to a full purge, which is slow and defeats the purpose. Also ensure your CDN respects stale-while-revalidate and does not collapse concurrent revalidation requests — enable request coalescing.

4. Edge Runtime: Compute at the Last Mile

Edge Runtime moves logic from a centralized origin to 300+ points of presence. The performance gain is not just latency; it is also resilience. An edge function that personalizes content based on geolocation or cookies does not need to round-trip to us-east-1.

Common use cases include: Middleware for authentication and redirects, A/B testing via cookies, geofencing, bot protection, and edge-rendered personalization. The trade-off is runtime limitations. Edge Runtime uses WinterCG APIs — fetch, Request, Response, crypto — but not fs, child_process, or native Node modules. Bundle size matters; keep it under 2MB compressed.

// middleware.ts — runs on every request at the edge
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export const config = { matcher: ["/dashboard/:path*", "/api/edge/:path*"] };

export function middleware(req: NextRequest) {
  const country = req.geo?.country ?? "US";
  const token = req.cookies.get("session")?.value;
  if (!token) return NextResponse.redirect(new URL("/login", req.url));
  const res = NextResponse.next();
  res.headers.set("x-geo-country", country);
  return res;
}

// app/api/edge/personalize/route.ts
export const runtime = "edge";
export async function GET(req: Request) {
  const city = req.headers.get("x-vercel-ip-city") ?? "unknown";
  return Response.json({ city, message: `Hello from ${city}!` });
}

From a CDN perspective, Edge Functions bypass traditional caching. They are not cached unless you explicitly set Cache-Control on their response. For performance, cache edge responses that are deterministic per region or user segment using Vary headers and CDN tiered caching. For example, cache a geolocation API for 60 seconds with Vary: x-geo-country.

Transport matters here. Edge Functions benefit disproportionately from modern protocols. Ensure your CDN negotiates HTTP/3 over QUIC at the edge — it reduces handshake latency and handles packet loss better for mobile users hitting edge compute. Pair this with CDN monitoring and observability to track edge function cold starts, CPU duration, and cache hit ratios separately from origin metrics.

5. Deployment Strategy Matrix

Choosing the right mode per route is an architectural decision. The wrong choice costs either build time, origin cost, or user latency. Use this matrix to map routes to CDN behavior.

Strategy Best For CDN Cache TTL Revalidation Origin Load
SSG Marketing, docs, blog index 1 year (immutable) On deploy only Zero after deploy
ISR (time) Product catalog, news feed 60–3600s + SWR Background after TTL Low, bursty
ISR (on-demand) CMS content, pricing Indefinite + tag purge Webhook via revalidateTag Minimal, precise
Edge Runtime Auth, personalization, A/B 0–60s or Vary-based Per-request compute None (edge compute)
SSR (Node) Private dashboards, checkout Bypass / private Per request High

Recommended hybrid architecture: Deploy SSG and ISR pages to edge cache with tiered caching and origin shield. Deploy Middleware and personalization to Edge Runtime. Keep authenticated SSR routes on Node serverless functions with Cache-Control: private, no-store and protect them via CDN token authentication. This isolates cacheable traffic (90%+) from dynamic traffic and lets you scale each independently.

6. Production Checklist for CDN + Next.js

When done correctly, your origin handles only cache misses and mutations. The CDN serves everything else from memory, 20ms from the user. That is the promise of Next.js on the edge — not just faster pages, but a fundamentally cheaper and more resilient architecture.

Next step: Audit your current Cache-Control headers with curl -I https://yourdomain.com/blog/slug and compare against the matrix above. If you see no-store on a static page or no stale-while-revalidate on ISR, you have an immediate optimization opportunity.

Frequently Asked Questions

How does ISR work with a CDN cache?

ISR stores the statically generated page at the CDN edge. The first request populates the cache. Subsequent requests are served instantly from the edge until revalidate expires. After expiry, the next request triggers background regeneration while serving stale content, then the CDN cache is updated atomically.

Should I use Edge Runtime or Node Runtime for CDN deployment?

Use Edge Runtime for lightweight, latency-sensitive logic like personalization, A/B testing, middleware, and geolocation. Use Node Runtime for heavy computation, large dependencies, or APIs requiring Node.js native modules. Many production apps use a hybrid: Edge for middleware and ISR pages, Node for API routes.

What is the best cache-control strategy for SSG pages on a CDN?

For SSG, use immutable caching with long TTLs: Cache-Control: public, max-age=31536000, immutable and CDN-Cache-Control with s-maxage. Since SSG files are content-hashed and deployed atomically, they can be cached indefinitely at the edge and browser. Purge only on new deployments.

How do I handle on-demand revalidation behind a CDN?

Use Next.js revalidateTag() or revalidatePath() with a secure webhook. When your CMS updates content, call the revalidation endpoint. The Next.js server purges the internal Data Cache and the CDN layer via cache tags. Ensure your CDN supports surrogate keys or cache tagging for precise invalidation without full purge.

References & Standards: OWASP CDN Security · Cloudflare documentation