Caching Strategien im Vergleich: SWR, TanStack Query und Apollo Client
AI generated
</>
{ }
React · SWR · TanStack Query · Apollo Client
Caching Strategien im Vergleich
SWR, TanStack Query und Apollo Client

Caching Strategien entscheiden darüber, wie oft eine React-Anwendung Daten neu lädt, wie schnell Änderungen sichtbar werden und wie viel Speicher der Client dafür verbraucht. SWR, TanStack Query und Apollo Client lösen dieselbe Grundaufgabe mit unterschiedlichen Caching Strategien, von einfachem Stale-While-Revalidate bis zur vollständigen Objektnormalisierung, mit spürbaren Konsequenzen für Konsistenz und Wartungsaufwand.

18 Min. Lesezeit Stale-While-Revalidate · Query-Keys · Normalisierung · Garbage Collection React 19 · SWR 2 · TanStack Query v5 · Apollo Client 3.x

1. Warum Caching Strategien den größten Performance-Hebel bilden

Bevor eine konkrete Bibliothek betrachtet wird, lohnt sich ein Blick auf das gemeinsame Grundproblem, das jede der drei Lösungen zu lösen versucht.

Die Caching Strategien einer React-Anwendung entscheiden über gefühlte Geschwindigkeit stärker als fast jede andere Architekturentscheidung. Eine Komponente, die bei jedem Mount neu vom Server lädt, fühlt sich langsam an, selbst wenn der Server in unter hundert Millisekunden antwortet, weil Nutzerinnen einen sichtbaren Ladezustand wahrnehmen. Eine durchdachte Caching-Strategie zeigt stattdessen sofort die zuletzt bekannten Daten an und aktualisiert im Hintergrund, was die Anwendung praktisch verzögerungsfrei wirken lässt.

SWR, TanStack Query und Apollo Client verfolgen unterschiedliche Caching Strategien, die auf den ersten Blick ähnlich wirken, sich in den Details aber deutlich unterscheiden: von der Adressierung einzelner Cache-Einträge über die Invalidierungslogik bis zur Frage, ob überhaupt Objektnormalisierung stattfindet. Dieser Artikel vergleicht die drei Ansätze entlang genau dieser Kriterien und zeigt, wann welche Caching-Strategie den größten praktischen Vorteil bringt.

Ein weiterer Grund, weshalb sich der genaue Vergleich lohnt, ist die Tatsache, dass alle drei Bibliotheken denselben Marketingbegriff verwenden, nämlich Caching, aber unterschiedliche technische Realitäten dahinter verbergen. Wer eine Bibliothek allein nach Bekanntheit oder GitHub-Sternen auswählt, übersieht häufig, dass die zugrunde liegende Caching Strategie eine völlig andere Antwort auf dieselbe Frage gibt, nämlich wie lange Daten gültig bleiben und wann sie erneuert werden.

2. SWR: Stale-While-Revalidate in seiner reinsten Form

SWR, entwickelt von Vercel, ist nach genau dem HTTP-Cache-Header-Konzept benannt, das es implementiert: Stale-While-Revalidate. Die Caching-Strategie zeigt sofort die im Cache vorhandenen, potenziell veralteten Daten an, während im Hintergrund eine neue Anfrage läuft, und aktualisiert die UI, sobald die Antwort eintrifft. Diese Caching Strategie ist bewusst minimalistisch gehalten: Ein Cache-Key, meist die URL, adressiert einen Eintrag, ohne komplexere Query-Objekte oder Normalisierung.

SWR wird oft als erste Caching-Bibliothek in kleineren Projekten oder Prototypen eingesetzt, gerade weil der Einstieg minimal ist und kaum Konzepte vorausgesetzt werden.

Diese Einfachheit ist SWRs größte Stärke und gleichzeitig seine größte Grenze. Für Anwendungen mit überwiegend unabhängigen Datenquellen, bei denen ein Objekt selten über mehrere unterschiedliche Endpoints geladen wird, ist die schlanke Caching-Strategie von SWR ausreichend und erzeugt minimalen Overhead. Für Anwendungen mit stark verflochtenen Datenmodellen, in denen dasselbe Objekt über mehrere Views hinweg konsistent bleiben muss, stößt diese Caching Strategie ohne zusätzliche manuelle Arbeit an ihre Grenzen.


// useUser.ts — SWR's minimal caching strategy, keyed by URL
import useSWR from "swr";

const fetcher = (url: string) => fetch(url).then((res) => res.json());

function useUser(userId: string) {
  return useSWR(`/api/users/${userId}`, fetcher, {
    revalidateOnFocus: true,
    dedupingInterval: 5000, // Ignore duplicate requests within 5s
  });
}

// Manual revalidation after a mutation, since SWR has no automatic normalization
import { mutate } from "swr";

async function updateUserName(userId: string, name: string) {
  await fetch(`/api/users/${userId}`, { method: "PATCH", body: JSON.stringify({ name }) });
  // Revalidate this specific cache key
  mutate(`/api/users/${userId}`);
}

SWR ist außerdem eng mit Next.js verwoben, wurde aber bewusst framework-unabhängig gehalten und funktioniert genauso gut in reinen Client-Side-React-Anwendungen. Für Teams, die bereits das Vercel-Ökosystem nutzen, ist die Integration oft nahtlos, weil Dokumentation und Beispiele häufig direkt auf Next.js-Patterns zugeschnitten sind, was den Einstieg in diese Caching Strategie zusätzlich beschleunigt.

3. TanStack Query: Query-Keys als Cache-Adressierung

TanStack Query erweitert das Stale-While-Revalidate-Prinzip von SWR um ein deutlich ausdrucksstärkeres Adressierungssystem: Query-Keys sind Arrays statt einzelner Strings, wodurch sich hierarchische Beziehungen zwischen Cache-Einträgen abbilden lassen, etwa ["users", userId, "posts"]. Diese Caching Strategie erlaubt es, mit invalidateQueries nicht nur einen exakten Key, sondern ganze Teilbäume von Query-Keys gezielt zu invalidieren, ohne jeden betroffenen Key einzeln aufzählen zu müssen.

Ein weiterer Unterschied zu SWR ist die eingebaute Unterstützung für Mutations als First-Class-Konzept mit onMutate, onError und onSettled, statt Mutations dem Entwickler komplett selbst zu überlassen. Diese Caching Strategie bringt strukturierte Werkzeuge für genau die Fälle mit, die bei SWR manuell nachgebaut werden müssten, etwa Optimistic Updates mit Rollback. Für mittelgroße bis große Anwendungen mit vielen Mutationen ist dieser strukturierte Ansatz meist der praktikablere.


// useUserPosts.ts — TanStack Query's hierarchical query-key strategy
import { useQuery, useQueryClient } from "@tanstack/react-query";

function useUserPosts(userId: string) {
  return useQuery({
    queryKey: ["users", userId, "posts"],
    queryFn: () => fetchUserPosts(userId),
    staleTime: 60_000, // Data considered fresh for 60s, no background refetch
  });
}

function useInvalidateUser(userId: string) {
  const queryClient = useQueryClient();
  return () => {
    // Invalidates the whole subtree: user data, posts, comments, everything nested
    queryClient.invalidateQueries({ queryKey: ["users", userId] });
  };
}

Ein oft übersehener Vorteil von TanStack Query ist die eingebaute Unterstützung für parallele und abhängige Queries über useQueries und die enabled-Option, mit der eine Query erst startet, sobald eine vorherige Query erfolgreich abgeschlossen ist. Diese Bausteine der Caching Strategie von TanStack Query decken Anwendungsfälle ab, die bei SWR häufig zusätzliche, selbstgeschriebene Koordinationslogik erfordern.

4. Apollo Client: Normalisierter Objektgraph statt Query-Cache

Apollo Client verfolgt eine fundamental andere Caching Strategie als SWR und TanStack Query: Statt Ergebnisse pro Anfrage oder Query-Key zu cachen, zerlegt InMemoryCache jede Antwort in einzelne, normalisierte Objekte, referenziert über __typename und id. Diese Caching-Strategie sorgt dafür, dass ein einzelnes Objekt, unabhängig davon, über welche Query es ursprünglich geladen wurde, überall im Cache konsistent bleibt, sobald es sich ändert.

Der Preis für diese Konsistenz ist zusätzliche Komplexität: Type Policies, keyFields und Feld-Level-merge-Funktionen müssen korrekt konfiguriert sein, damit die Normalisierung tatsächlich funktioniert. Für Anwendungen, in denen dasselbe Produkt oder derselbe Nutzer in Dutzenden von Views auftaucht, zahlt sich diese aufwendigere Caching Strategie aus, weil ein einzelnes Update automatisch überall propagiert wird, ohne dass Entwickler manuell nachdenken müssen, welche Query-Keys betroffen sein könnten.

Diese objektbasierte Caching Strategie zeigt ihre Stärke besonders bei Formularen, die dasselbe Feld eines Objekts in mehreren Ansichten gleichzeitig bearbeitbar machen, etwa ein Inline-Edit in einer Tabelle und ein vollständiges Bearbeitungsformular in einem Modal. Beide Ansichten lesen automatisch denselben normalisierten Cache-Eintrag, sodass eine Änderung an einer Stelle sofort und ohne zusätzlichen Code an der anderen Stelle sichtbar wird.

5. Invalidierung im Vergleich: Tags, Keys und Objekt-IDs

Die drei Bibliotheken invalidieren Cache-Einträge auf grundlegend unterschiedliche Weise. SWR invalidiert über den exakten Cache-Key, meist die URL, was bedeutet, dass Entwickler bei einer Mutation genau wissen müssen, welche URLs betroffen sind. TanStack Query invalidiert über Query-Key-Präfixe, was ganze Teilbäume auf einmal erfasst und deutlich weniger manuelle Buchhaltung erfordert, solange die Key-Struktur von Anfang an durchdacht ist.

Apollo Client invalidiert implizit, indem es das betroffene Objekt direkt im normalisierten Cache aktualisiert, statt eine Query zu invalidieren: Jede Komponente, die dieses Objekt über irgendeine Query referenziert, sieht die Änderung automatisch. Diese Caching Strategie braucht kein explizites Invalidierungssystem für einzelne Objektänderungen, dafür aber sorgfältige Konfiguration der Normalisierung selbst, damit dieser Automatismus überhaupt greift.


// Comparing invalidation across the three caching strategies
// SWR: invalidate by exact key
mutate(`/api/users/${userId}`);

// TanStack Query: invalidate a whole subtree by key prefix
queryClient.invalidateQueries({ queryKey: ["users", userId] });

// Apollo Client: no explicit invalidation call needed for a single field change,
// cache.modify updates the object directly, all referencing views update automatically
cache.modify({
  id: cache.identify({ __typename: "User", id: userId }),
  fields: { name: () => newName },
});

Ein praktischer Zwischenweg für Teams, die TanStack Query nutzen, aber gelegentlich von objektbasierter Konsistenz profitieren möchten, ist eine dünne, selbstgeschriebene Normalisierungsschicht, die bekannte Entitäten wie Nutzer oder Produkte anhand ihrer ID in einer zentralen Map hält und bei jedem Query-Ergebnis synchron aktualisiert. Das ist kein Ersatz für Apollos vollautomatische Caching Strategie, reduziert aber Inkonsistenzen bei kritischen, häufig wiederverwendeten Entitäten spürbar, ohne gleich das komplette Caching-Modell zu wechseln.

6. Staleness-Konfiguration: staleTime, dedupingInterval und fetchPolicy

Jede der drei Bibliotheken bietet einen eigenen Mechanismus, um zu definieren, wie lange Daten als frisch gelten, bevor ein Hintergrund-Refetch ausgelöst wird. SWR nutzt dedupingInterval, um mehrfache identische Anfragen innerhalb eines kurzen Zeitfensters zu einer einzigen zusammenzufassen, revalidiert aber standardmäßig bei jedem Fenster-Fokus und jeder Netzwerk-Wiederverbindung. TanStack Query nutzt staleTime als expliziten Zeitraum, während dessen Daten als frisch gelten und kein automatischer Refetch stattfindet, was feingranularere Kontrolle pro Query erlaubt.

Apollo Client konfiguriert dieses Verhalten über fetchPolicy, etwa cache-first, cache-and-network oder network-only, wobei diese Einstellung eher grundsätzlich pro Query als über eine Zeitdauer gesteuert wird. Diese unterschiedlichen Modelle für dieselbe grundlegende Caching Strategie spiegeln unterschiedliche Philosophien wider: SWR optimiert für Einfachheit mit sinnvollen Defaults, TanStack Query für explizite Kontrolle, und Apollo Client für Konsistenz des Objektgraphen über die Zeitdauer hinweg.

Ein praktischer Tipp für alle drei Bibliotheken: unterschiedliche Datenarten sollten unterschiedliche Staleness-Werte bekommen. Nutzerprofile ändern sich selten und vertragen ein hohes staleTime von mehreren Minuten, während Preisinformationen in einem Warenkorb nahezu in Echtzeit aktuell sein müssen. Eine einheitliche, globale Staleness-Konfiguration für die gesamte Caching Strategie übersieht diese Unterschiede und führt entweder zu unnötigen Refetches oder zu spürbar veralteten Daten an kritischer Stelle.

7. Speicherverhalten und Garbage Collection

Ohne Garbage Collection würde jede Caching Strategie unbegrenzt wachsen, sobald eine Anwendung über Stunden hinweg genutzt wird und immer neue Daten in den Cache gelangen. TanStack Query löst dies über gcTime, früher cacheTime genannt: Ungenutzte Query-Ergebnisse, auf die keine aktive Komponente mehr zugreift, werden nach Ablauf dieser Zeitspanne automatisch aus dem Speicher entfernt. SWR verfolgt einen ähnlichen Ansatz, ist aber standardmäßig großzügiger und erfordert oft explizite Konfiguration für aggressive Speicherbereinigung.

Apollo Client bietet cache.gc() als manuell auslösbare Garbage Collection, die alle Objekte entfernt, auf die keine aktive Query mehr verweist, muss aber typischerweise nach cache.evict()-Aufrufen explizit aufgerufen werden. Für Anwendungen mit sehr großen Datenmengen und langen Sitzungen, etwa Admin-Dashboards, die stundenlang geöffnet bleiben, ist dieses Speicherverhalten ein oft unterschätzter Faktor bei der Wahl der Caching Strategie, weil ein unkontrolliert wachsender Cache selbst bei korrekter Datenanzeige die Anwendung im Laufe der Zeit spürbar verlangsamt.

Ein oft übersehener Nebeneffekt fehlender Garbage Collection zeigt sich in Single-Page-Applications mit clientseitigem Routing: Wechselt eine Nutzerin zwischen vielen unterschiedlichen Detailseiten, sammeln sich ohne Bereinigung die Cache-Einträge aller jemals besuchten Seiten an, auch wenn die Nutzerin längst zu einem völlig anderen Bereich der Anwendung navigiert ist. Eine sinnvoll konfigurierte Caching Strategie mit aktiver Garbage Collection hält den Speicherverbrauch dagegen proportional zur tatsächlich aktiven Nutzung, nicht zur gesamten Interaktionshistorie einer Sitzung.

8. Persistenz und Offline-Verhalten der drei Caches

Alle drei Bibliotheken unterstützen Cache-Persistenz über Storage-Adapter, mit denen der In-Memory-Cache periodisch in localStorage oder IndexedDB gesichert wird, um bei einem Seiten-Reload sofort mit bekannten Daten starten zu können. TanStack Query bietet dafür persistQueryClient als offizielles Plugin, SWR nutzt einen konfigurierbaren provider, und Apollo Client bietet apollo3-cache-persist als community-getragene Erweiterung.

Für echte Offline-Funktionalität, bei der Mutationen während einer Netzwerkunterbrechung zwischengespeichert und später automatisch nachgesendet werden, bietet TanStack Query mit seiner Mutation-Queue-Funktionalität den ausgereiftesten eingebauten Mechanismus unter den dreien. Apollo Client bietet mit der Apollo Link-Architektur zwar die Bausteine für eine eigene Offline-Queue, verlangt dafür aber deutlich mehr eigene Implementierungsarbeit als die eingebaute Lösung von TanStack Query.

Für Progressive Web Apps mit expliziten Offline-Anforderungen lohnt es sich, die Cache-Persistenz unabhängig von der gewählten Caching Strategie früh im Projekt zu planen, statt sie nachträglich einzubauen. Die Wahl des Storage-Adapters, IndexedDB für größere Datenmengen, localStorage für kleinere, beeinflusst direkt, wie viele Daten offline verfügbar bleiben und wie schnell die Anwendung nach einem Cold Start wieder nutzbar ist.

9. Caching Strategien im direkten Vergleich

Die folgende Tabelle fasst die entscheidenden Unterschiede der drei Caching Strategien zusammen und dient als Entscheidungsgrundlage für die nächste Projektarchitektur. Sie ersetzt keine individuelle Analyse des eigenen Datenmodells, macht aber die zentralen Kompromisse auf einen Blick sichtbar.

Kriterium SWR TanStack Query Apollo Client
Cache-Adressierung URL-String Hierarchische Query-Keys Objektbasiert (Typename:id)
Normalisierung Keine Keine Vollständig
Mutation-Werkzeuge Minimal, manuell onMutate/onError/onSettled optimisticResponse, cache.modify
Bundle-Größe Sehr klein Klein bis mittel Groß
Lernkurve Niedrig Mittel Hoch
Idealer Einsatzbereich Einfache REST-Anwendungen REST und gemischte Datenquellen Komplexe, GraphQL-basierte Datenmodelle

Ein Aspekt, der in der Tabelle nicht direkt sichtbar wird, ist die Migrationsfreundlichkeit: Der Wechsel von SWR zu TanStack Query ist meist unkompliziert, weil beide auf ähnlichen Konzepten wie Hooks und Cache-Keys basieren. Ein Wechsel von oder zu Apollo Client ist deutlich aufwendiger, weil er in der Regel auch einen Wechsel der zugrunde liegenden Datenschicht von REST zu GraphQL oder umgekehrt bedeutet, was weit über den reinen Austausch der Caching Strategie hinausgeht.

Keine dieser Caching Strategien ist in jedem Kontext überlegen. SWR eignet sich für Teams, die minimalen Overhead und schnellen Einstieg wollen. TanStack Query bietet die beste Balance aus Kontrolle und Einfachheit für die meisten REST- und gemischten Anwendungen. Apollo Client lohnt sich, sobald ein GraphQL-Datenmodell mit stark verflochtenen Objekten über viele Views hinweg konsistent gehalten werden muss.

Diese Entscheidung sollte, wie bei jeder grundlegenden Architekturfrage, dokumentiert und im Team geteilt werden, damit spätere Erweiterungen der Anwendung dieselbe Caching Strategie konsequent weiterführen, statt mehrere konkurrierende Ansätze parallel im selben Projekt zu etablieren.

Mironsoft

Caching-Architektur für React mit SWR, TanStack Query und Apollo Client

Die richtige Caching-Strategie für eure Datenmenge?

Wir analysieren euer Datenmodell und empfehlen die Caching-Bibliothek, die zu Konsistenzanforderungen, Teamgröße und Bundle-Budget tatsächlich passt.

Cache-Audit

Analyse bestehender Invalidierungslogik auf redundante und fehlende Refetches

Migration

Wechsel zwischen SWR, TanStack Query und Apollo Client ohne Big-Bang-Risiko

Speicher-Tuning

gcTime, cache.gc() und Persistenz für lang laufende Sitzungen konfigurieren

10. Zusammenfassung

Die Wahl zwischen SWR, TanStack Query und Apollo Client bleibt am Ende eine Frage der tatsächlichen Anforderungen an Konsistenz, nicht der reinen Popularität einer Bibliothek.

Wer unsicher ist, sollte mit der kleinsten sinnvollen Caching Strategie für den aktuellen Anwendungsfall starten und erst bei konkretem Konsistenz- oder Performance-Bedarf zu einer aufwendigeren Lösung wechseln, statt von Beginn an die komplexeste Option zu wählen.

Die drei verglichenen Caching Strategien lösen dieselbe Grundaufgabe mit unterschiedlichem Aufwand und unterschiedlicher Präzision. SWRs Stale-While-Revalidate über einfache URL-Keys eignet sich für schlanke Anwendungen mit überwiegend unabhängigen Datenquellen. TanStack Querys hierarchische Query-Keys bieten mehr Kontrolle bei Invalidierung und strukturierte Mutation-Werkzeuge, ohne die Komplexität einer vollständigen Objektnormalisierung.

Unabhängig von der gewählten Bibliothek gilt: Unterschiedliche Datenarten verdienen unterschiedliche Staleness-Werte, und Garbage Collection sollte nie dem Zufall überlassen werden, besonders in lang laufenden Sitzungen wie Admin-Dashboards.

Apollo Clients normalisierter Objektgraph bleibt die aufwendigste, aber auch konsistenteste Caching Strategie für stark verflochtene GraphQL-Datenmodelle. Staleness-Konfiguration über staleTime, dedupingInterval oder fetchPolicy, Garbage Collection über gcTime oder cache.gc(), und Persistenz-Adapter für Offline-Szenarien runden das jeweilige Caching-Modell ab. Die richtige Wahl hängt weniger von persönlicher Präferenz ab als von der tatsächlichen Struktur der Daten und der Größe der Anwendung.

Ein Wechsel der Caching Strategie im laufenden Betrieb bleibt möglich, sollte aber immer schrittweise und mit klaren Erfolgskriterien pro Migrationsabschnitt erfolgen, statt die gesamte Datenschicht in einem einzigen, riskanten Schritt auszutauschen.

Caching Strategien im Vergleich — Das Wichtigste auf einen Blick

SWR

Minimalistisches Stale-While-Revalidate über URL-Keys, ideal für schlanke Anwendungen.

TanStack Query

Hierarchische Query-Keys, strukturierte Mutations, gute Balance aus Kontrolle und Einfachheit.

Apollo Client

Vollständige Objektnormalisierung, ideal für komplexe GraphQL-Datenmodelle.

Entscheidung

Datenmodell-Komplexität und Konsistenzanforderungen entscheiden, nicht Bekanntheit der Bibliothek.

Alle drei Caching Strategien profitieren von datenartspezifischer Staleness-Konfiguration statt eines globalen Einheitswertes für die gesamte Anwendung.

Die folgenden häufig gestellten Fragen fassen die wichtigsten Entscheidungspunkte rund um Caching Strategien noch einmal kompakt zusammen.

11. FAQ: Caching Strategien im Vergleich

1Was bedeutet Stale-While-Revalidate?
Der Cache zeigt sofort bekannte Daten, während im Hintergrund eine neue Anfrage läuft und die UI danach aktualisiert.
2Warum keine Normalisierung bei SWR?
SWR ist bewusst minimalistisch und cached pro URL-Key, statt Objekte im Payload zu erkennen und zu normalisieren.
3Vorteil hierarchischer Query-Keys?
Ganze Teilbäume lassen sich mit einem invalidateQueries-Aufruf invalidieren, statt jeden Key einzeln aufzuzählen.
4Wann lohnt sich Apollos normalisierter Cache?
Wenn dasselbe Objekt in vielen Views konsistent bleiben muss und Updates automatisch propagiert werden sollen.
5Was passiert ohne Garbage Collection?
Der Cache wächst unbegrenzt und der Speicherverbrauch steigt über Stunden hinweg spürbar an.
6staleTime vs. gcTime?
staleTime bestimmt Frische ohne Refetch, gcTime bestimmt, wie lange ungenutzte Daten im Speicher bleiben.
7Bietet SWR Optimistic Updates?
Ja, über mutate mit optimisticData, aber weniger strukturiert als TanStack Querys onMutate/onError.
8Beste Strategie für Offline-Funktionalität?
TanStack Querys Mutation-Queue-Funktionalität ist der ausgereifteste eingebaute Mechanismus dafür.
9Apollo Client für REST-APIs?
Technisch möglich, aber die Normalisierungsvorteile entfalten sich erst mit echtem GraphQL-Schema.
10Wechsel zwischen den Strategien sinnvoll?
Nur schrittweise, Feature für Feature, mit klarer Validierung nach jedem Migrationsabschnitt.