Headless-Shops sind 2026 schnell - solange die Store API mitspielt. Genau hier setzt Shopware ab Version 6.7 an: Ausgewählte, nicht-mutierende Store-API-Endpoints sind nun cachebar und liefern echte Cache-Control-Header aus. Damit verschiebt sich ein großer Teil der Last vom Origin auf Reverse Proxy, CDN und das Frontend. Der Hebel ist erheblich: Bereits eine 0,1 Sekunde schnellere Antwort steigerte die Conversion im Handel um 8,4 % und den durchschnittlichen Bestellwert um 9,2 % (Deloitte) - und gute Core Web Vitals heben die Conversion um 15 bis 30 % (web.dev). Dieser Leitfaden zeigt, wie Sie in Nuxt- und Composable-Frontends N+1-Probleme vermeiden, Client-Caching sauber setzen und Stale-While-Revalidate produktiv nutzen - rein auf der Caching-Schicht der Store API, abgegrenzt von der reinen Architektur-Frage.

Warum Store-API-Caching der Performance-Hebel 2026 ist

In einem Headless-Setup rendert das Frontend - etwa Nuxt oder ein Composable-UI - die Oberfläche und holt sich Daten über die Store API. Anders als die klassische Storefront, die ihren HTTP-Cache und ESI mitbringt, liefen Store-API-Antworten lange ungecacht direkt aus dem Origin. Jeder Seitenaufruf, jede Kategorie, jeder Produktblock erzeugte einen frischen PHP-Request samt Datenbankzugriff. Bei wachsendem Traffic wird das zum Flaschenhals.

Die Zahlen machen den Druck deutlich: 53 % der mobilen Nutzer verlassen eine Seite, die länger als 3 Sekunden lädt (Google/SOASTA), und pro zusätzlicher Sekunde Ladezeit sinkt die Conversion um rund 7 % (Conductor). Bereits 100 ms Mehrzeit können rund 1 % Umsatz kosten (Amazon via Conductor). Wer die Store API cachebar macht, adressiert genau diese Latenz - nicht im Frontend-Code, sondern an der teuersten Stelle: der Server-Antwortzeit.

Abgrenzung zu Architektur-Themen

Dieser Artikel behandelt ausschließlich die Caching-Schicht der Store API. Wenn Sie zunächst die grundsätzliche Entscheidung für ein entkoppeltes Frontend treffen wollen, lesen Sie Headless Commerce mit Shopware und Composable Commerce. Hier geht es um die konkrete Caching-Mechanik, nicht um die Architektur-Frage.

Was sich ab Shopware 6.7 konkret ändert

Mit dem überarbeiteten Caching-System (eingeführt über das CACHE_REWORK-Feature-Flag und seit den 6.7.5/6.7.6-Releases produktiv ausgerollt) markiert Shopware ausgewählte Store-API-Routen als cachebar. Cachebar ist eine Route, wenn sie das Routen-Attribut '_httpCache' => true trägt - also nicht-mutierende Endpoints, die keine sensiblen, kundenindividuellen Daten zurückgeben (Shopware Docs).

Cachebare Routen liefern standardmäßig folgenden Cache-Control-Header (Shopware Docs):

Cache-Control (cachebare Route)
Cache-Control: public, max-age=0, s-maxage=1800,
               stale-while-revalidate=86400, stale-if-error=7200

# Nicht-cachebare Route:
Cache-Control: no-cache, private

s-maxage=1800

Shared Caches (Reverse Proxy, CDN) halten die Antwort 30 Minuten frisch. max-age=0 zwingt den Browser dagegen zur Revalidierung - so steuern Sie Server- und Client-Cache getrennt.

stale-while-revalidate=86400

Bis zu 24 Stunden darf der Cache eine veraltete Antwort sofort ausliefern und parallel im Hintergrund erneuern. Der Nutzer wartet in der Regel nicht auf den Origin.

stale-if-error=7200

Fällt der Origin aus, serviert der Cache für 2 Stunden weiter die letzte gute Antwort - ein eingebautes Sicherheitsnetz für Spitzenlast.

public

Die Antwort darf von gemeinsam genutzten Caches gespeichert werden - die Voraussetzung dafür, dass ein Reverse Proxy oder CDN überhaupt eingreift.

Damit getrennte Sprachen, Währungen und Kontexte nicht denselben Cache-Eintrag teilen, nutzt Shopware statt Cookies drei dedizierte Header, die im Vary-Header geführt werden: sw-currency-id, sw-language-id und sw-context-hash (Shopware Docs). So bekommt ein DE/EUR-Besucher so nicht versehentlich die EN/USD-Antwort aus dem Cache.

GET statt POST: Voraussetzung fürs Caching

HTTP-Caches speichern in der Regel nur GET-Antworten. Viele Store-API-Aufrufe nutzten bisher POST, um komplexe Filter- und Such-Kriterien im Body zu übergeben. Damit diese Requests cachebar werden, können Kriterien jetzt als komprimierter, kodierter String im GET-Parameter _criteria mitgegeben werden - intern als JSON -> gzip -> base64url kodiert (Shopware Docs).

store-api-client.ts
// Cachebarer GET-Request mit kodierten Kriterien
const criteria = {
  limit: 24,
  associations: { cover: {}, manufacturer: {} },
  filter: [{ type: 'equals', field: 'active', value: true }]
}

const encoded = encodeCriteria(criteria) // JSON -> gzip -> base64url
const res = await $fetch(
  `/store-api/product?_criteria=${encoded}`,
  { headers: { 'sw-access-key': key } }
)
// Antwort traegt jetzt einen public Cache-Control-Header
Kriterien kanonisieren

Die SDK-Helfer kanonisieren die Kriterien vor dem Kodieren - gleiche Anfrage, gleicher String, gleicher Cache-Key. Wer Kriterien selbst zusammenbaut, sollte Reihenfolge und Felder stabil halten, sonst sinkt die Hit-Rate, weil semantisch identische Requests unterschiedliche Cache-Einträge erzeugen.

N+1-Probleme in Nuxt und Composable-Frontends vermeiden

Das häufigste Performance-Leck im Headless-Frontend ist nicht der fehlende Cache, sondern das N+1-Muster: Eine Listenkomponente rendert 40 Produkte und feuert pro Produkt einen eigenen Detail-Call. Aus einem Request werden 41 - und selbst mit Caching bleibt das ineffizient, weil jeder Call eigene Latenz, eigene Verbindung und eigene Revalidierung mitbringt.

MusterCalls pro ListenseiteLatenz-RisikoCache-Effizienz
N+1 (pro Produkt 1 Call)41HochGering
Gebatcht (associations)1-2NiedrigHoch
Gebatcht + SWR1-2 (oft aus Cache)Sehr niedrigSehr hoch

Die Lösung liegt in der Store API selbst: Statt Nachladen pro Produkt fordern Sie verbundene Daten über associations und includes in einem einzigen Aufruf an. Das reduziert nicht nur die Anzahl der Requests, sondern auch die übertragene Datenmenge - includes schneidet die Antwort auf die wirklich benötigten Felder zu.

useProductListing.ts
// Statt 40 Einzel-Calls: ein gebatchter, schlanker Request
const { data } = await useAsyncData('listing', () =>
  storeApi('/store-api/product-listing/' + categoryId, {
    method: 'GET',
    query: { _criteria: encodeCriteria({
      associations: { cover: {}, options: {} },
      includes: {
        product: ['id', 'name', 'calculatedPrice', 'cover'],
        product_media: ['url']
      }
    }) }
  })
)
// useAsyncData dedupliziert parallele Aufrufe automatisch
  • Batching statt Nachladen: Verbundene Entitäten über associations in einem Call holen, nicht pro Produkt einzeln.
  • Payload schlank halten: Mit includes nur die Felder anfordern, die das UI tatsächlich rendert - weniger Bytes, schnelleres Parsen.
  • Request-Deduplizierung:useAsyncData/useFetch in Nuxt bündeln identische parallele Aufrufe zu einem Request mit gemeinsamem Key.
  • Pagination vor Prefetch: Erst sichtbare Seite laden, Folgeseiten erst bei Bedarf oder im Idle prefetchen.

Client-Caching im Frontend richtig setzen

Server-Caching adressiert die Antwortzeit, Client-Caching die Navigation. Ein Composable-Frontend kann bereits geladene Store-API-Antworten im Speicher halten und bei erneutem Aufruf sofort aus dem normalisierten Cache rendern - während im Hintergrund revalidiert wird. So fühlt sich der Seitenwechsel instant an. Studien beziffern den Effekt: React Server Components und schlanke Hydration reduzieren das JavaScript-Bundle um 40 bis 60 % (digitalapplied) und verbessern damit direkt INP und LCP.

Wichtig ist die Abstimmung mit den Server-Headern. Da max-age=0 gesetzt ist, revalidiert der Browser - aber ein bedingter Request mit ETag oder If-None-Match endet bei unveränderten Daten in einem schlanken 304 Not Modified statt einer vollen Antwort. Das spart Bandbreite, ohne Frische zu opfern.

Memory-Cache

Bereits geladene Listen und Produkte im State-Store halten. Wiederkehrende Navigation rendert ohne neuen Netzwerk-Roundtrip.

ETag / 304

Bedingte Requests nutzen: unveränderte Daten liefern 304 Not Modified - der Body wird gar nicht erst übertragen.

Prefetch im Idle

Wahrscheinliche nächste Routen (z. B. Top-Kategorie) im Leerlauf vorab laden, damit der Klick instant wirkt.

Personalisierte Daten nicht cachen

Warenkorb, Kundenkonto und Preise mit kundenspezifischen Rabatten gehören NICHT in einen public-Cache. Diese Endpoints bleiben no-cache, private. Trennen Sie cachebare Katalogdaten strikt von kontextabhängigen Daten - sonst riskieren Sie, dass ein Nutzer fremde oder veraltete personalisierte Inhalte sieht.

Stale-While-Revalidate produktiv nutzen

Stale-While-Revalidate (SWR) ist der wirksamste Hebel für wahrgenommene Geschwindigkeit. Das Prinzip: Läuft s-maxage ab, liefert der Cache die veraltete Antwort trotzdem sofort aus und stößt parallel im Hintergrund eine Aktualisierung an. Niemand wartet auf den Origin - der nächste Besucher bekommt bereits die frische Version. In der Praxis senken SWR-Header die Origin-Zugriffe um rund 65 % (digitalapplied).

Stale-While-Revalidate entkoppelt die wahrgenommene Geschwindigkeit von der tatsächlichen Origin-Antwortzeit: Der Nutzer sieht praktisch durchgehend sofort Inhalt, die Aktualisierung passiert unsichtbar im Hintergrund.

XICTRON Entwicklungsteam

Die Shopware-Defaults sind bewusst großzügig gewählt: stale-while-revalidate=86400 (24 Stunden) und stale-if-error=7200 (2 Stunden) sorgen dafür, dass selbst bei seltenem Traffic oder kurzem Origin-Ausfall noch Inhalte ausgeliefert werden. Für schnelllebige Inhalte - etwa Verfügbarkeiten oder Aktionspreise - lassen sich pro Route engere Werte über benannte Caching-Policies konfigurieren, die Cache-Control je Bereich (storefront, store_api) und Route bilden.

BFF-Antwort für aggregierte Daten
# Eigener Backend-for-Frontend-Layer, der mehrere
# Store-API-Quellen bündelt, kann engere Werte setzen:
Cache-Control: public, s-maxage=60, stale-while-revalidate=600
Die SWR-Faustregel

Setzen Sie s-maxage so kurz wie nötig für Frische und stale-while-revalidate so lang wie möglich für Verfügbarkeit. So bleibt die Hit-Rate hoch, ohne dass Nutzer veraltete Inhalte über längere Zeit sehen - der Hintergrund-Refresh hält den Cache aktuell.

Cache-Invalidierung: frisch, ohne Flaschenhals

Ein Cache ist nur so gut wie seine Invalidierung. Aendert sich ein Preis oder Lagerbestand, muss der betroffene Eintrag gezielt verfallen - nicht der gesamte Cache. Shopware arbeitet hier mit Cache-Tags, die das Object-Cache, den HTTP-Cache und - sauber konfiguriert - auch den Edge-Layer synchronisieren. So bleibt die Hit-Rate hoch, ohne dass veraltete Daten hängenbleiben.

  1. Tag-basiert invalidieren: Bei Produktänderung nur die zugehörigen Cache-Tags löschen, nicht pauschal flushen.
  2. SWR als Puffer: Selbst direkt nach Ablauf liefert der Cache sofort aus und holt frische Daten im Hintergrund - keine Lastspitze auf dem Origin.
  3. Monitoring der Hit-Rate: Eine sinkende Hit-Rate ist oft das erste Signal für fragmentierte Cache-Keys oder zu enge TTLs - regelmäßig die Performance überwachen.
  4. Kontext-Header prüfen: Falsch gesetzte Vary-Header fragmentieren den Cache und senken die Hit-Rate drastisch.
Zusammenspiel mit Edge-Caching

Store-API-Caching und Edge-Caching für Shopware ergänzen sich: Die Store API liefert die Cache-Control-Header, der Edge-Node setzt sie global um. Wer beides kombiniert, bringt API-Antworten weltweit unter die 50-ms-Marke.

Messen, was zählt: Headless-Performance-Audit

Caching wirkt nur, wenn es gemessen wird. Ein Headless-Performance-Audit prüft, welche Store-API-Routen tatsächlich cachebar sind, wie hoch die reale Hit-Rate liegt, ob N+1-Muster im Frontend lauern und ob die Vary-Header sauber gesetzt sind. Die Wirkung ist messbar: Edge- und API-Caching reduzieren Origin-Requests typischerweise um 85 bis 95 % (digitalapplied) und die TTFB um 60 bis 80 % (Cloudflare).

Gleichzeitig gilt: Ein schlecht geplanter Headless-Umbau kann Organic Traffic um 20 bis 40 % kosten (digitalapplied), wenn Rendering, Caching und SEO nicht zusammenpassen. Genau deshalb gehören Caching-Schicht und Core-Web-Vitals-Optimierung in dieselbe Analyse. XICTRON prüft beide Ebenen gemeinsam und leitet konkrete, priorisierte Maßnahmen ab.

  • Cachebare Store-API-Routen identifiziert und _httpCache korrekt gesetzt
  • GET mit _criteria statt POST für cachebare Abfragen
  • N+1-Muster im Nuxt/Composable-Frontend durch Batching ersetzt
  • Vary-Header (sw-currency-id, sw-language-id, sw-context-hash) korrekt
  • Personalisierte Endpoints strikt von public-Cache getrennt
  • Tag-basierte Invalidierung und Hit-Rate-Monitoring etabliert

Backend-for-Frontend: mehrere Quellen sauber bündeln

Viele Headless-Seiten kombinieren mehrere Store-API-Antworten zu einer Ansicht: eine Produktliste, dazu das Navigationsmenü, Cross-Selling und ein CMS-Block. Werden diese Aufrufe direkt aus dem Browser gefeuert, summieren sich Latenzen und Verbindungen. Ein Backend-for-Frontend (BFF) bündelt sie serverseitig zu einer einzigen, vorbereiteten Antwort - und kann dabei eigene, engere Cache-Control-Werte setzen, weil es die Frische der Mischung selbst kennt.

Der Effekt ist doppelt: Erstens entfällt für den Client der Wasserfall aus Einzelrequests, zweitens wird die aggregierte Antwort selbst cachebar. Ein BFF mit public, s-maxage=60, stale-while-revalidate=600 liefert die Komposition 60 Sekunden frisch und danach bis zu zehn Minuten als Stale-Antwort, während im Hintergrund neu zusammengesetzt wird. Wichtig ist, dass das BFF die Kontext-Header (sw-language-id, sw-currency-id, sw-context-hash) durchreicht und im Vary führt, damit die Aggregation nicht über Sprach- und Währungsgrenzen hinweg verwechselt wird.

BFF nicht überladen

Ein BFF sollte komponieren, nicht personalisieren. Sobald kundenspezifische Daten wie Warenkorb oder individuelle Preise einfließen, fällt die Antwort aus dem public-Cache. Trennen Sie den cachebaren Katalog-Teil vom personalisierten Teil und laden Sie Letzteren separat im Client nach - so bleibt der große, teure Teil der Seite cachebar.

In der Praxis lohnt sich das BFF besonders für Einstiegs- und Kategorieseiten mit viel statischem Katalog-Anteil. Produktdetailseiten profitieren ebenfalls, solange Verfügbarkeit und Preis nicht sekundenaktuell sein müssen. Wo doch, kombiniert man einen cachebaren Grundzustand mit einem kleinen, nicht gecachten Live-Request für den volatilen Teil.

Typische Caching-Fehler und wie Sie sie vermeiden

Caching wirkt nur, wenn es konsequent gedacht ist. In Headless-Projekten begegnen uns wiederholt dieselben Muster, die die Hit-Rate drücken oder - schlimmer - falsche Daten ausliefern. Die gute Nachricht: Sie lassen sich mit klaren Regeln vermeiden.

Unstrukturierte Cache-Keys

Wenn Kriterien in wechselnder Reihenfolge oder mit überflüssigen Feldern kodiert werden, entstehen viele leicht unterschiedliche Keys für dieselbe Anfrage. Lösung: Kriterien vor dem Kodieren kanonisieren und nur tatsächlich genutzte Felder anfragen.

Personalisierung im public-Cache

Wer kundenspezifische Preise oder Empfehlungen versehentlich in eine cachebare Route mischt, riskiert, dass ein Besucher fremde Daten sieht. Lösung: personalisierte Bestandteile strikt in private-Routen oder Client-Calls auslagern.

Zu aggressive Invalidierung

Ein pauschaler Cache-Flush bei jeder Änderung setzt die Hit-Rate auf null und erzeugt Lastspitzen. Lösung: tag-basiert nur betroffene Einträge invalidieren und Stale-While-Revalidate als Puffer nutzen.

Fehlende Vary-Header

Ohne korrekte Vary-Angaben teilen sich Sprachen und Währungen denselben Eintrag - oder der Cache fragmentiert unnötig. Lösung: genau die drei Kontext-Header führen, die der Antwort zugrunde liegen.

Hinzu kommt ein organisatorischer Punkt: Caching ist kein einmaliges Setup, sondern ein laufender Prozess. Sortimente, Preise und Aktionen ändern sich, das Frontend wird weiterentwickelt, neue Routen kommen hinzu. Deshalb gehört die Hit-Rate ins Monitoring und die Caching-Strategie in jede größere Release-Planung. So bleibt der Performance-Gewinn dauerhaft erhalten, statt nach wenigen Wochen wieder zu verpuffen.

Schrittweise einführen: Caching ohne Risiko aktivieren

Store-API-Caching lässt sich gefahrlos und schrittweise aktivieren, weil das überarbeitete Caching-System hinter einem Feature-Flag liegt und die Defaults konservativ gewählt sind. In der Praxis empfiehlt sich ein gestufter Rollout: erst auf einer Staging-Umgebung messen, dann auf gut cachebaren Katalogrouten beginnen und die Hit-Rate beobachten, bevor weitere Routen folgen. So sehen Sie den Effekt, bevor er produktiv wirkt, und können die TTL-Werte an Ihr Sortiment anpassen.

Besonders wichtig ist die Reihenfolge: Zuerst die N+1-Muster im Frontend beseitigen, dann das Server-Caching aktivieren. Wer zuerst cacht, ohne das Frontend zu entzerren, cacht lediglich viele kleine, ineffiziente Antworten - der Gewinn bleibt hinter dem Möglichen zurück. Erst die Kombination aus gebatchten, schlanken Requests und cachebaren Antworten entfaltet die volle Wirkung. Diese Reihenfolge spiegelt sich auch in einem Headless-Performance-Audit wider, das vom Frontend-Code bis zur Cache-Konfiguration durchgeht.

Nicht zuletzt zahlt sich Caching auf die Betriebskosten aus: Weniger Origin-Requests bedeuten weniger CPU-Last, kleinere Server und ruhigere Lastspitzen zu Aktionszeiten. Was als reine Performance-Maßnahme beginnt, entlastet damit auch das Hosting - ein Effekt, der mit wachsendem Traffic deutlicher wird und die Investition in eine saubere Caching-Schicht über die reine Geschwindigkeit hinaus rechtfertigt.

So könnte Ihr Headless-Shop aussehen:

Consumer ElectronicsDemo

Elektronik-Shop

Dieses Designbeispiel zeigt, wie ein schneller, entkoppelter Online-Shop mit klarer Produktnavigation und sehr kurzen Antwortzeiten aussehen kann. Wir entwickeln individuelle Headless-Lösungen, bei denen Frontend, Store API und Caching-Schicht präzise aufeinander abgestimmt sind.
HeadlessStore APICachingPerformance
Projekt besprechen
Demo
Quellen und Studien

Dieser Artikel basiert auf Daten und Dokumentation aus: Shopware Documentation (Store API, Caching Strategy ADR, Release Notes 6.7), Deloitte (Milliseconds Make Millions), web.dev, Google/SOASTA, Conductor (Amazon-Studie), digitalapplied (Headless Commerce 2026) und Cloudflare. Die genannten Zahlen können je nach Zeitpunkt, Shop und Messmethode variieren.

Cachebar sind in der Regel nicht-mutierende GET-Endpoints, die keine kundenindividuellen Daten zurückgeben - etwa Produkt-, Listing-, Kategorie- und Navigationsabfragen. Eine Route ist cachebar, wenn sie das Attribut _httpCache trägt. Warenkorb, Konto und personalisierte Preise bleiben typischerweise no-cache, private (Shopware Docs).

Der Standard für cachebare Routen lautet public, max-age=0, s-maxage=1800, stale-while-revalidate=86400, stale-if-error=7200. s-maxage steuert Shared Caches (30 Min frisch), max-age=0 zwingt den Browser zur Revalidierung, SWR liefert bis zu 24 Stunden veraltete Inhalte sofort aus und erneuert im Hintergrund. Die Werte lassen sich pro Route anpassen.

Statt pro Produkt einen eigenen Call zu feuern, holen Sie verbundene Daten über associations und schneiden die Antwort mit includes zu - idealerweise in einem einzigen gebatchten Request. In Nuxt dedupliziert useAsyncData/useFetch parallele Aufrufe zusätzlich. So sinkt die Zahl der Calls erfahrungsgemäß deutlich.

HTTP-Caches speichern in der Regel nur GET-Antworten. Damit Abfragen mit komplexen Kriterien cachebar werden, können die Kriterien als komprimierter String im GET-Parameter _criteria übergeben werden (JSON, gzip, base64url). POST-Requests werden üblicherweise nicht gecacht.

Kurzzeitig ja - genau das ist gewollt. SWR liefert nach Ablauf der Frische sofort die letzte Antwort und erneuert sie im Hintergrund, sodass der nächste Besucher bereits die aktuelle Version sieht. Für schnelllebige Inhalte sollten Sie s-maxage und SWR-Fenster bewusst kürzer setzen oder die Route nicht cachen.

Ja. Bereits ein Reverse Proxy vor dem Shopware-Origin profitiert von den Cache-Control-Headern und entlastet die PHP- und Datenbankschicht spürbar. Ein global verteiltes Edge-Netz verstärkt den Effekt zusätzlich, ist aber keine Voraussetzung. Die genaue Wirkung hängt von Traffic, Cache-Strategie und Shop-Struktur ab.

Tags:#Store API#Caching#Headless#Performance#Shopware