Home › Modern Web › CDN for Vue and Nuxt
Modern Web

CDN for Vue and Nuxt: Hybrid Rendering and Edge-Side Caching

By Sarah Mitchell, Edge Computing Engineer September 8, 2026 8 min read

Vue and Nuxt 3 have moved beyond simple single-page apps. With hybrid rendering, you can prerender, server-render, and incrementally regenerate pages from the same codebase. But without a CDN-aware caching strategy, you lose the performance and cost benefits. This guide shows how to deploy Nuxt hybrid rendering to the edge correctly.

Nuxt 3 unifies several rendering modes under one router. A single application can serve a static landing page, a server-rendered dashboard, and an ISR-regenerated blog post. The CDN is what makes this hybrid model scalable. It decides what to cache, for how long, and when to revalidate at the edge, close to your users. Misconfigure it and you either serve stale personalized data or bypass the cache entirely and overload your origin.

Hybrid Rendering in Nuxt 3: Beyond SSR vs SSG

Traditional thinking forced a choice: Single Page App (SPA) for interactivity, Static Site Generation (SSG) for speed, or Server-Side Rendering (SSR) for SEO and dynamic data. Nuxt 3 eliminates that tradeoff with hybrid rendering powered by Nitro and routeRules.

Each route declares its own behavior. Nitro then builds the optimal output: prerendered HTML, a serverless function, or a cached payload with a revalidation timer. The CDN simply respects the headers Nitro generates.

The key insight is granularity. Your / and /about can be prerendered, /blog/** can be ISR with a 3600s TTL, and /account can be SSR with no cache. This per-route control is what makes CDN caching strategies so effective for Vue applications.

Expert Tip: Don't think in pages, think in freshness requirements. Ask: How stale can this route be before it hurts UX or SEO? A product price might tolerate 60 seconds, a legal disclaimer can be cached for a year.

Why a CDN Is Essential for Nuxt Performance

Nuxt SSR is fast, but origin rendering still adds 80-300ms of compute plus network latency. A CDN collapses that to 15-40ms by serving from edge memory. More importantly, it protects your origin from traffic spikes.

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

Three CDN capabilities matter most for Vue/Nuxt:

1. Edge Compute for SSR

Modern CDNs run Nuxt server functions at the edge using Cloudflare Workers, Netlify Edge, Vercel Edge, or AWS Lambda@Edge. Instead of a single origin in us-east-1, your SSR runs in 300+ PoPs. This reduces Time to First Byte (TTFB) and improves Core Web Vitals, especially Largest Contentful Paint (LCP) and Interaction to Next Paint (INP).

2. Tiered Caching for Payloads

Nuxt 3 splits rendering into HTML and JSON payloads (/_payload.json). A CDN should cache both. When a user navigates client-side, Nuxt fetches only the payload, not the full HTML. Caching payloads at the edge makes subsequent navigations feel instant.

3. Asset Optimization

Vue chunks, images, and fonts should be immutable and cached for a year. Nuxt hashes filenames automatically (/_nuxt/entry.abc123.js). Your CDN should serve these with Cache-Control: public, max-age=31536000, immutable. Pair this with image optimization at the edge for responsive NuxtImg delivery without origin transforms.

Edge-Side Caching Architecture

Edge-side caching means the CDN, not the browser, is the primary cache. The browser may hold a short cache, but the edge holds the authoritative copy and serves it to thousands of users.

Nuxt Hybrid Rendering Edge Flow Diagram showing request flow from browser to edge CDN to origin with cache layers BROWSER Vue Hydration max-age: 60s ◐ REQUEST EDGE CDN Cache: HIT → Serve Cache: MISS → Fetch s-maxage / SWR / ISR ORIGIN FETCH NITRO ORIGIN Nuxt SSR / ISR routeRules RENDER → CACHE HEADERS Client Navigation Edge Payload Cache Serverless / Node
Hybrid rendering flow: Browser requests hit the edge first. On HIT, the CDN serves cached HTML/payload. On MISS or stale-while-revalidate, the edge fetches from Nitro origin and caches with route-specific headers.

Caching Strategies by Rendering Mode

Not every route should be cached equally. Use this matrix to map Nuxt rendering modes to CDN cache directives. The goal is to maximize hit ratio without risking personalized data leakage.

Route Type Nuxt routeRule CDN Strategy Example Header
Static Marketing SSG prerender: true Immutable at edge, long browser cache public, max-age=31536000, immutable
Blog / Docs ISR isr: 3600 Edge cache 1h, SWR background refresh public, s-maxage=3600, stale-while-revalidate=86400
Product Listing SWR swr: 60 Edge 60s, serve stale while revalidating public, s-maxage=60, stale-while-revalidate=600
Authenticated SSR ssr: true + bypass Bypass edge cache, private browser cache private, no-store or CDN-Cache-Control: no-store
Assets STATIC Auto-hashed by Vite Year-long immutable public, max-age=31536000, immutable

For ISR/SWR routes, Nuxt automatically adds Cache-Control and CDN-Cache-Control separation when deployed to a preset that supports it. This lets you keep s-maxage long at the edge while browsers revalidate more frequently. Always verify your CDN respects CDN-Cache-Control or Surrogate-Control — Cloudflare, Fastly, and Vercel do.

Understanding DNS resolution and Anycast routing also helps here. A fast DNS lookup ensures the user hits the nearest edge PoP before any caching logic even runs.

Configuring Nuxt for CDN Deployment

Configuration lives in nuxt.config.ts. The routeRules object is the single source of truth for hybrid behavior. Nitro translates these rules into headers and prerender manifests at build time.

// nuxt.config.ts - Hybrid rendering with edge caching
export default defineNuxtConfig({
  nitro: {
    preset: 'cloudflare-pages' // or 'vercel', 'netlify', 'aws-lambda'
  },
  routeRules: {
    // Static - prerendered at build, cached forever at edge
    '/': { prerender: true },
    '/about': { prerender: true },
    '/contact': { prerender: true },

    // ISR - cached 1 hour at edge, regenerated in background
    '/blog/**': { isr: 3600 },

    // SWR - fresh for 60s, serve stale for 10min while revalidating
    '/products/**': { swr: 60, headers: {
      'CDN-Cache-Control': 'public, s-maxage=60, stale-while-revalidate=600'
    }},

    // SSR - dynamic, but cacheable for anonymous users
    '/api/products/**': { headers: {
      'Cache-Control': 'public, s-maxage=60, stale-while-revalidate=300'
    }},

    // Private - never cache at edge
    '/dashboard/**': { ssr: true, headers: {
      'Cache-Control': 'private, no-store',
      'CDN-Cache-Control': 'no-store'
    }},
    '/api/auth/**': { headers: { 'CDN-Cache-Control': 'no-store' } }
  },
  experimental: {
    payloadExtraction: true // Enables _payload.json caching
  }
})

For fine-grained control, set headers inside server routes or middleware:

// server/routes/api/products.get.ts
export default defineEventHandler(async (event) => {
  const products = await fetchProducts()

  // Cache at edge for 60s, allow stale for 5min during revalidation
  setHeader(event, 'Cache-Control', 'public, max-age=10, s-maxage=60')
  setHeader(event, 'CDN-Cache-Control', 'public, s-maxage=60, stale-while-revalidate=300')
  setHeader(event, 'Vary', 'Accept-Encoding')

  return products
})

Key details to get right:

Cache Invalidation, Purging, and Observability

Caching is easy; invalidation is hard. With hybrid rendering you have three invalidation paths:

1. Time-based revalidation (SWR/ISR): The most reliable. No purge needed — the edge serves stale content while Nitro regenerates in the background. Set stale-while-revalidate to cover regeneration time. For a blog, s-maxage=3600, stale-while-revalidate=86400 means users never wait for a rebuild.

2. On-demand purge via API: When content changes immediately (price update, CMS publish), call your CDN purge API. Most providers support surrogate key or URL purging. Tag Nuxt responses with Surrogate-Key or Cache-Tag headers and purge by tag:

// Add cache tags for granular purging
setHeader(event, 'Cache-Tag', 'products, product-123, category-shoes')
setHeader(event, 'CDN-Cache-Control', 'public, s-maxage=300')

// Later, purge via API (example: Cloudflare)
// POST /zones/:id/purge_cache { tags: ["product-123"] }

3. Build-time invalidation: Prerendered routes only update on new deployment. Use this for truly static content. For everything else, prefer ISR/SWR.

Finally, observe hit rates. A healthy Nuxt CDN deployment should see 85-95% edge hit ratio for anonymous traffic. Monitor via CDN observability tools and track performance metrics like TTFB, cache status (x-cache: HIT/MISS), and origin offload. If your hit ratio is below 70%, you are likely over-bypassing or missing CDN-Cache-Control headers. If users see stale data too long, shorten s-maxage or implement tag-based purging.

Deployment Checklist

  • Choose a Nitro preset matching your CDN (cloudflare-pages, vercel, netlify, aws-amplify)
  • Define routeRules for every route pattern, not just defaults
  • Test headers locally with curl -I and at edge with curl -I -H "CF-Cache-Status: HIT"
  • Enable payload extraction and cache /_payload.json
  • Set immutable caching for /_nuxt/* assets
  • Implement purge-by-tag for CMS-driven routes
  • Monitor hit ratio and TTFB by route, not just globally

When hybrid rendering and edge caching work together, Nuxt delivers the best of both worlds: the SEO and freshness of SSR with the speed and resilience of static. Your Vue app feels instant because most requests never reach the origin — they are served from memory, a few milliseconds away from the user.

Frequently Asked Questions

Should I use SSR or SSG for my Nuxt site behind a CDN?

Use hybrid rendering. Prerender static marketing pages with SSG for maximum CDN hit rate, use SSR with edge caching for personalized or frequently updated pages, and ISR/SWR for content that can be stale for a few minutes like blogs or product listings. This gives you static speed where possible and dynamic freshness where needed.

How do I cache Nuxt SSR responses at the edge without serving stale user data?

Set CDN-Cache-Control with s-maxage for shared edge caches and keep browser cache short. Use Vary headers or cache keys based on cookies and authorization, and bypass cache entirely for authenticated routes via routeRules or CDN bypass rules. Never cache responses that contain user-specific data with a public directive.

What is the difference between CDN-Cache-Control and Cache-Control in Nuxt?

Cache-Control affects both browser and CDN caches. CDN-Cache-Control (or Surrogate-Control) targets only the edge cache, letting you keep a long s-maxage at the edge while using a short max-age in the browser. This allows fast invalidation for users while maintaining high edge hit rates.

How does Nuxt routeRules work with a CDN?

Nuxt routeRules define per-route rendering and caching behavior at build time. Rules like prerender, isr, swr, and headers generate the correct cache headers and static payloads so the CDN can cache each route optimally without custom edge logic. Nitro translates these rules into the proper output for your deployment preset.

References & Standards: OWASP CDN Security · RFC 7234