<v/>
{ }
Nuxt 3 · Caching · Edge Deployment · Nitro · Performance · CDN
Nuxt Caching und Edge-Strategien
verstehen — von Nitro bis zum CDN-Edge

Nuxt 3 mit Nitro bietet mehrere Caching-Schichten, die unabhängig voneinander konfiguriert werden können — Server-seitiger Nitro-Cache, ISR mit Stale-While-Revalidate, CDN-Cache-Control-Headers und Edge-Deployment. Die richtige Kombination dieser Schichten macht den Unterschied zwischen einer Anwendung mit 800 ms TTFB und einer mit 40 ms.

20 Min. Lesezeit Nitro-Cache · ISR · routeRules · Cache-Control · Stale-While-Revalidate · Edge Nuxt 3 · Cloudflare · Vercel · Node.js

1. Die Caching-Schichten in Nuxt 3

Das Nuxt Caching-Modell besteht aus mehreren unabhängigen Schichten, die unterschiedliche Teile des Request-Response-Zyklus abdecken. Die erste und tiefste Schicht ist der Nitro-Cache: Server-seitiges Caching von Server-Route-Responses in-Memory oder in einem konfigurierten Storage-Backend. Die zweite Schicht sind CDN-Cache-Control-Headers, die dem vorgelagerten CDN mitteilen, wie lange es eine Response zwischenspeichern darf. Die dritte Schicht ist ISR (Incremental Static Regeneration), die statisch vorgerenderte HTML-Seiten mit einer konfigurierbaren Revalidierungszeit kombiniert. Die vierte Schicht ist das Browser-Caching über HTTP-Headers.

Diese Schichten sind unabhängig voneinander konfigurierbar — aber sie interagieren. Eine Server Route mit Nitro-Cache von 60 Sekunden, die einen Cache-Control: public, max-age=3600-Header setzt, wird vom CDN eine Stunde gecacht, unabhängig vom Nitro-Cache-Ablauf. Das ist gewollt, wenn die Daten sich tatsächlich selten ändern — und problematisch, wenn der Nitro-Cache frische Daten hat, das CDN aber noch veraltete. Das Verständnis dieser Interaktion ist der Schlüssel zu einer korrekten Nuxt Caching-Strategie, die weder Daten veraltet liefert noch Performance-Potenzial verschenkt.

Der erste Schritt bei der Planung einer Nuxt Edge-Strategie ist daher eine Klassifizierung der Content-Typen: Wie oft ändern sich diese Daten? Sind sie nutzerabhängig (personalisiert) oder öffentlich? Können veraltete Daten für eine gewisse Zeit toleriert werden? Diese Fragen bestimmen, welche Caching-Schicht(en) für jeden Content-Typ sinnvoll sind. Personalisierte Daten dürfen niemals in einem gemeinsamen CDN-Cache landen. Öffentliche, selten ändernde Daten sind ideal für aggressive Caching-Strategien über alle Schichten.

2. Nitro-Cache: Server-seitiges Caching für Server Routes

Der Nitro Cache ist die leistungsfähigste und flexibelste Caching-Schicht in der Nuxt-3-Architektur. Mit defineCachedEventHandler statt defineEventHandler wird eine Server Route gecacht. Der Cache-Key, die Cache-Dauer und das Cache-Storage-Backend sind pro Route konfigurierbar. Standardmäßig cacht Nitro im Memory — schnell, aber nicht über mehrere Server-Instanzen geteilt. Mit einem externen Storage-Backend wie Redis wird der Cache verteilt und überlebt Server-Neustarts.

Die getKey-Funktion im Nitro-Cache-Konfigurationsobjekt ist entscheidend für die Cache-Granularität. Eine Server Route ohne getKey cacht alle Requests unter demselben Key — problematisch bei Routen, die Query-Parameter oder Locale-Header verarbeiten. Eine getKey-Funktion, die Query-Parameter, Accept-Language-Header oder Nutzer-Segmente einschließt, erstellt granulare Cache-Einträge, die korrekte Responses für verschiedene Request-Varianten liefern. Das ist der Unterschied zwischen einem korrekten und einem kaputten Cache.


// server/api/products/featured.get.ts
// Nitro cached route — respects locale and currency query params in cache key
export default defineCachedEventHandler(async (event) => {
  const query = getQuery(event)
  const locale = (query.locale as string) ?? 'de'
  const currency = (query.currency as string) ?? 'EUR'

  // Fetch from external API or DB — result will be cached per locale+currency
  const products = await $fetch(`https://api.example.com/products/featured`, {
    headers: { 'Accept-Language': locale },
    query: { currency },
  })

  // Set CDN cache headers in addition to Nitro cache
  setResponseHeaders(event, {
    'Cache-Control': 'public, max-age=300, stale-while-revalidate=60',
  })

  return products
}, {
  maxAge: 60 * 5,  // 5 minutes in Nitro cache
  // Cache key includes locale and currency — separate entry per combination
  getKey: (event) => {
    const q = getQuery(event)
    return `featured:${q.locale ?? 'de'}:${q.currency ?? 'EUR'}`
  },
  // Store in Redis for distributed caching across multiple server instances
  base: 'redis',
})

3. routeRules: Caching auf Page-Ebene konfigurieren

routeRules in der nuxt.config.ts ist das zentrale Werkzeug für seitenweises Nuxt Caching. Sie erlauben es, für jede URL-Pattern eine eigene Rendering- und Caching-Strategie zu definieren — ohne dass eine einzelne Seite manuell konfiguriert werden muss. Das macht routeRules zum idealen Werkzeug für hybride Anwendungen, in denen verschiedene Seitentypen verschiedene Caching-Anforderungen haben.

Die wichtigsten routeRules-Optionen für Nuxt Caching: prerender: true rendert die Seite einmalig beim Build zu einer statischen HTML-Datei. isr: N implementiert ISR mit einer Revalidierungszeit von N Sekunden — die Seite wird beim ersten Request gerendert, gecacht, und nach N Sekunden bei der nächsten Anfrage im Hintergrund revalidiert. cache: { maxAge: N } cacht die SSR-Response für N Sekunden im Nitro-Cache. ssr: false schaltet auf Client-only-Rendering um — kein Server-seitiges Rendering, kein Caching auf Server-Seite.


// nuxt.config.ts — route-level caching strategy per URL pattern
export default defineNuxtConfig({
  routeRules: {
    // Marketing pages: pre-rendered once at build time — CDN serves static HTML
    '/':           { prerender: true },
    '/about':      { prerender: true },
    '/blog':       { prerender: true },

    // Blog posts: ISR — rendered on first request, revalidated every 10 minutes
    '/blog/**':    { isr: 600 },

    // Product pages: ISR with shorter interval for fresher data
    '/products/**': { isr: 120 },

    // API routes: Nitro-cached responses, CDN-cacheable
    '/api/catalog/**': { cache: { maxAge: 300 } },

    // User-specific pages: SSR only, no caching (personalized content)
    '/account/**': { ssr: true, cache: false },

    // Admin: SPA mode, no SSR, no server cache
    '/admin/**':   { ssr: false },
  },
})

4. ISR in Nuxt 3: Incremental Static Regeneration richtig umsetzen

Incremental Static Regeneration (ISR) ist das Caching-Muster, das den besten Kompromiss zwischen statischer Performance und dynamischer Aktualität bietet. Das Prinzip: Die erste Anfrage für eine URL löst einen Server-Render aus, das Ergebnis wird gecacht. Alle folgenden Anfragen innerhalb der Revalidierungszeit bekommen die gecachte Version — mit Server-Speed, ohne erneuten Render. Nach Ablauf der Revalidierungszeit wird beim nächsten Request die gecachte Version ausgeliefert (Stale-While-Revalidate), während im Hintergrund ein neuer Render gestartet wird. Der nächste Request bekommt die frische Version.

Der Nuxt ISR-Mechanismus über routeRules: { '/products/**': { isr: 300 } } implementiert genau dieses Stale-While-Revalidate-Muster. Der Nutzer wartet niemals auf einen Render — er bekommt immer eine gecachte Version. Die maximale "Veraltungszeit" ist durch den ISR-Wert begrenzt. Für Produktkataloge, Blog-Seiten und andere Inhalte, die sich gelegentlich ändern, aber keine Echtzeit-Aktualität erfordern, ist ISR die optimale Caching-Strategie: schnell wie statisch, aktuell wie SSR, ohne die Infrastruktur-Komplexität von manuellem Cache-Busting.

5. Cache-Control-Headers: CDN-Caching steuern

HTTP Cache-Control-Headers sind die Schnittstelle zwischen dem Nuxt-3-Server und vorgelagerten CDNs wie Cloudflare, AWS CloudFront oder Fastly. Korrekte Headers erlauben dem CDN, Responses zu cachen und direkt aus dem Edge-Netzwerk auszuliefern — ohne den Origin-Server zu kontaktieren. Das reduziert die Server-Last und die Latenz für geographisch verteilte Nutzer drastisch.

Die wichtigsten Cache-Control-Direktiven für Nuxt Edge-Strategien: public erlaubt CDN-Caching von Responses (ohne: CDN cacht standardmäßig nicht). max-age=N definiert die Cache-Lebensdauer in Sekunden aus Sicht des CDN. stale-while-revalidate=M erlaubt das Ausliefern veralteter Responses für M Sekunden, während im Hintergrund revalidiert wird. s-maxage=N definiert die Cache-Lebensdauer nur für CDNs (überschreibt max-age für Shared Caches). no-store verhindert jegliches Caching — Pflicht für personalisierte und sensitive Responses.

6. Cache-Invalidierung: wann und wie Cache-Einträge löschen

Cache-Invalidierung ist das schwierigste Problem beim Nuxt Caching — nicht technisch, sondern konzeptuell. Die Frage "wann muss welcher Cache-Eintrag ungültig werden?" hat keine einfache universelle Antwort. Sie hängt von den Datenabhängigkeiten ab: Wenn ein Produkt aktualisiert wird, müssen der Nitro-Cache für /api/products/[id], die ISR-gecachte /products/[id]-Seite und potenziell die CDN-gecachte Antwort invalidiert werden. Das sind drei verschiedene Systeme mit drei verschiedenen Invalidierungsmechanismen.

Im Nitro-Cache lässt sich ein einzelner Cache-Eintrag programmatisch löschen: useStorage('cache').removeItem(key) entfernt den Eintrag, der nächste Request triggert einen neuen Fetch. Für CDN-Cache ist Invalidierung über die CDN-API nötig — Cloudflare Cache Purge API, Vercel Revalidation Token oder AWS CloudFront Invalidation. Diese CDN-Invalidierungen können aus einer Nuxt-Server-Route ausgelöst werden, die von einem Webhook des Content-Management-Systems aufgerufen wird. Das Muster: CMS ändert Inhalt → Webhook → Nuxt-Route invalidiert Nitro-Cache und CDN-Cache → nächste Page-View bekommt frischen Content.


// server/api/_invalidate.post.ts
// Webhook endpoint — called by CMS when content changes
// Protected by shared secret to prevent unauthorized cache clears
export default defineEventHandler(async (event) => {
  // Verify webhook signature
  const secret = getHeader(event, 'x-webhook-secret')
  if (secret !== process.env.WEBHOOK_SECRET) {
    throw createError({ statusCode: 401, message: 'Unauthorized' })
  }

  const body = await readBody(event)
  const { type, id } = body  // e.g. { type: 'product', id: 'abc-123' }

  if (type === 'product') {
    // 1. Invalidate Nitro cache for this product's API route
    const storage = useStorage('cache')
    await storage.removeItem(`nitro:handlers:/api/products/${id}:product:${id}`)

    // 2. Trigger ISR revalidation for the product page
    // Nuxt ISR: setting isr: 0 in routeRules for a request forces fresh render
    await $fetch(`/products/${id}`, {
      headers: { 'x-nuxt-revalidate': process.env.REVALIDATE_SECRET ?? '' }
    })

    // 3. Purge CDN cache (Cloudflare example)
    await $fetch(`https://api.cloudflare.com/client/v4/zones/${process.env.CF_ZONE}/purge_cache`, {
      method: 'POST',
      headers: { Authorization: `Bearer ${process.env.CF_TOKEN}` },
      body: { files: [`https://example.com/products/${id}`] },
    })
  }

  return { success: true, invalidated: `${type}:${id}` }
})

7. Edge Deployment mit Nitro: Cloudflare Workers und Vercel Edge

Nuxt Edge-Deployment mit Nitro bedeutet, die Nuxt-Anwendung nicht auf einem zentralen Server auszuführen, sondern auf Edge-Nodes weltweit — geographisch nahe an den Nutzern. Cloudflare Workers, Vercel Edge Functions und ähnliche Dienste führen JavaScript direkt am CDN-PoP aus. Die Latenz für den ersten Byte sinkt von 200–800 ms (Origin-Request) auf 10–50 ms (Edge-Request), weil kein geographischer Umweg zum Origin-Server nötig ist.

Das Nitro-Preset für Cloudflare Workers (nitro: { preset: 'cloudflare-workers' }) kompiliert den gesamten Server-Code zu einem einzigen Worker-Script, das ohne V8-Node.js-APIs auskommt. Das ist eine wichtige Einschränkung: Node.js-spezifische APIs (fs, path, native Module) funktionieren im Edge-Runtime nicht. Bibliotheken müssen Edge-kompatibel sein. Das ist der häufigste Grund, warum Edge-Deployments scheitern — Abhängigkeiten, die intern Node.js-APIs verwenden. Die Lösung: Edge-Kompatibilität im npm-Paket prüfen oder Server-Middleware auf Edge-kompatible Alternativen umstellen.

8. Nitro Storage: verteilter Cache mit Redis und KV-Stores

Nitro Storage ist das abstrakte Interface, das den Nitro Cache mit verschiedenen Backend-Storages verbindet. In der Entwicklung ist das In-Memory-Storage ausreichend. In der Produktion mit mehreren Server-Instanzen oder Edge-Deployment braucht man ein verteiltes Storage-Backend: Redis für klassisches Server-Deployment, Cloudflare KV oder Vercel KV für Edge-Deployments. Die Konfiguration in nuxt.config.ts via nitro.storage ist konsistent — der Application-Code ändert sich nicht, nur die Backend-Konfiguration.

Redis als Nitro-Storage-Backend bietet gegenüber In-Memory-Cache drei entscheidende Vorteile: Der Cache überlebt Server-Neustarts und Deployments. Mehrere Server-Instanzen teilen denselben Cache — kein Cold-Start-Problem beim Horizontal-Scaling. Redis unterstützt natürlich TTL, sodass Nitro-Cache-Einträge automatisch ablaufen, ohne manuelle Cleanup-Logik. Die Latenz zu einem lokalen Redis-Server (< 1 ms) ist vernachlässigbar gegenüber dem CPU-Aufwand eines SSR-Renders. Das Verhältnis von Cache-Hit-Rate zu Rendering-Overhead macht Redis-backed Nitro-Cache besonders für SSR-Seiten mit hohem Traffic wirtschaftlich.

9. Nuxt Caching-Strategien im Vergleich

Die Wahl der richtigen Nuxt Caching-Strategie hängt von Content-Typ, Update-Frequenz und Personalisierungsanforderungen ab. Die folgende Tabelle zeigt die wichtigsten Strategien und ihre optimalen Einsatzgebiete.

Strategie Konfiguration Optimales Einsatzgebiet TTFB-Erwartung
Statisches Pre-rendering prerender: true Docs, Landing Pages, Blog (selten geändert) ~20 ms (CDN-Edge)
ISR / SWR isr: 300 Produkt-, News-, Blog-Seiten mit regelmäßigen Updates ~30–80 ms (gecacht)
Nitro-Cache SSR cache: { maxAge: 60 } Öffentliche Seiten mit mittlerer Update-Frequenz ~50–150 ms (Server)
SSR ohne Cache cache: false Personalisierte Seiten, Checkout, Profil ~300–800 ms (Origin)
Client-only (SPA) ssr: false Admin, Dashboards, Auth-geschützte UIs Shell sofort, Daten via API

Die wichtigste Optimierung in der Praxis: statische und gecachte Seiten so weit wie möglich nach vorne schieben, SSR ohne Cache nur für Content einsetzen, der sich in Echtzeit ändern muss oder nutzerspezifisch ist. Eine Produktseite, die für alle Nutzer identisch ist, braucht kein volles SSR ohne Cache — ISR mit einem 5-Minuten-Intervall ist 10-mal schneller und belastet den Origin-Server um 99 % weniger. Diese Entscheidung pro Seitentyp zu treffen ist der größte Performance-Hebel in einer Nuxt Caching-Strategie.

Mironsoft

Nuxt 3 Performance, Caching-Strategien und Edge-Deployment-Architektur

Nuxt-3-Anwendungen, die schnell sind — messbar und reproduzierbar?

Wir analysieren TTFB, Cache-Hit-Rates und CDN-Konfigurationen in bestehenden Nuxt-Projekten und implementieren Nitro-Caching, ISR und Edge-Strategien, die den Unterschied in echten Messwerten zeigen.

Caching-Audit

TTFB-Analyse, Cache-Hit-Rate-Messung und Identifikation von Caching-Lücken

routeRules-Strategie

ISR, Nitro-Cache und CDN-Headers pro Seitentyp konfigurieren und testen

Edge-Deployment

Nitro-Presets für Cloudflare Workers oder Vercel Edge — inklusive Kompatibilitäts-Audit

10. Zusammenfassung

Das Nuxt Caching-Modell bietet mehrere unabhängige Schichten: Nitro-Cache für Server-Route-Responses, routeRules für seitenweises Caching, ISR für Stale-While-Revalidate-Verhalten, Cache-Control-Headers für CDN-Steuerung und Edge-Deployment für geographisch minimierte Latenz. Die richtige Kombination hängt von der Content-Klassifizierung ab: öffentlich vs. personalisiert, statisch vs. dynamisch, häufige vs. seltene Änderungen.

Die größten Performance-Gewinne entstehen durch konsequente Anwendung der Caching-Hierarchie: Statisches Pre-rendering wo möglich, ISR wo Aktualität wichtig ist, SSR ohne Cache nur wo personalisierte Echtzeit-Daten nötig sind. Cache-Invalidierung über Webhooks und programmatische Nitro-Storage-Zugriffe ermöglicht die manuelle Invalidierung bei Content-Updates, ohne Cache-Timeouts abwarten zu müssen. Edge-Deployment mit Nitro-Presets für Cloudflare oder Vercel reduziert die TTFB für globale Nutzer auf Millisekunden — der größte einzelne Performance-Hebel für international genutzte Nuxt Edge-Anwendungen.

Nuxt Caching und Edge-Strategien — Das Wichtigste auf einen Blick

Nitro-Cache

defineCachedEventHandler mit maxAge und granularem getKey. Redis-Backend für verteilten Cache über mehrere Server-Instanzen.

ISR / Stale-While-Revalidate

routeRules: { '/products/**': { isr: 300 } } — gecachte Version sofort, Revalidierung im Hintergrund. Ideal für Produkt- und Blog-Seiten.

Cache-Invalidierung

Webhook → Server Route → Nitro-Storage-Eintrag löschen + CDN Purge API. CMS-gesteuerte Invalidierung ohne Timeout-Wartezeiten.

Edge Deployment

nitro.preset: 'cloudflare-workers' oder 'vercel-edge'. Kein Node.js-API-Zugriff — Edge-Kompatibilität aller Abhängigkeiten prüfen.

11. FAQ: Nuxt Caching und Edge-Strategien

1Nitro-Cache vs. CDN-Cache — was ist der Unterschied?
Nitro-Cache: server-seitig, vermeidet DB-Zugriff. CDN-Cache: vorgelagert, Nuxt-Server wird nicht kontaktiert. Beide unabhängig konfigurierbar und ergänzend.
2ISR vs. reines SSG?
SSG: alle Seiten einmalig beim Build. ISR: on-demand beim ersten Request, Revalidierung im Hintergrund. ISR skaliert auf tausende Seiten ohne Build-Zeit-Explosion.
3Personalisierte Seiten vor CDN-Caching schützen?
Cache-Control: private, no-store setzen. routeRules: cache: false. Kein ISR für personalisierte Routen. CDN respektiert diese Header.
4Nitro-Cache programmatisch invalidieren?
useStorage('cache').removeItem(key) — key entspricht dem getKey()-Wert. Nächster Request triggert neuen Fetch und Cache-Eintrag.
5Einschränkungen Edge Deployment?
Kein Node.js-API-Zugriff (fs, path, native Module). Bibliotheken müssen Edge-kompatibel sein. Dauerhafter Cache: KV-Store oder Redis nötig.
6Warum ist getKey im Nitro-Cache so wichtig?
Ohne getKey: alle Requests unter demselben Key — Nutzer A sieht Response von Nutzer B. getKey muss alle Request-Variablen (Query-Params, Locale) einschließen.
7Redis als Nitro-Storage konfigurieren?
nitro.storage.redis.driver: 'redis', url: REDIS_URL in nuxt.config. Im Handler: base: 'redis'. Automatische TTL entsprechend maxAge — kein manueller Cleanup.
8Was ist stale-while-revalidate?
Gecachte (veraltete) Response sofort ausliefern, Revalidierung im Hintergrund starten. Kein Warten. Sinnvoll wenn kurze Veraltungszeiten tolerierbar sind.
9Cache-Hit-Rate messen?
Nitro: Logging ob Handler erreicht wird. CDN: CF-Cache-Status Header prüfen. Cloudflare Analytics, Vercel Analytics für Edge-Monitoring.
10Caching-Strategie für E-Commerce?
Startseite + Kategorien: ISR 5–15 Min. Produktseiten: ISR 2–5 Min + Webhook-Invalidierung. Checkout/Konto: SSR, Cache-Control: private. API: Nitro-Cache + CDN public.