TanStack DB: Der reaktive Client-Store, der Dashboards sofortig macht

TanStack DB Complete Guide: Live-Queries, optimistic Mutations, Sub-Millisekunden-Reaktivität mit Differential Dataflow. Beta mit 3M+ wöchentlichen Downloads. Echte Produktionsbeispiele.

Huifer
Huifer
18. September 202610 min read
Auch verfügbar auf:English · 中文

Geschrieben von Huifer, Solo-Entwickler und Maintainer von TanStack Ship. Seit 2024 habe ich mehr als 12 SaaS-Dashboards auf Cloudflare Workers entwickelt. Das schlimmste Performance-Problem, das ich hatte, war ein Abrechnungs-Analytics-Dashboard, das nach jeder Mutation 8 Filterkombinationen aktualisierte – 8 Refetch-Aufrufe auslöste, auf 8 Netzwerkantworten wartete und 8 Loading-States rendere. Ich habe es im März 2026 mit TanStack DB neu geschrieben. Das Dashboard aktualisiert jetzt alle 8 Panels in unter 1ms nach jeder Mutation, bevor überhaupt eine Netzwerkanfrage gesendet wird. Das Refetch läuft im Hintergrund. Der Nutzer sieht bei Filteränderungen nie einen Loading-Spinner. Diese Erfahrung hat geprägt, wie ich über reaktive Client-seitige Daten denke – und warum TanStack DB das richtige Tool für datenintensive Dashboards ist.

Verifizierte Quellen: TanStack DB Overview · TanStack DB on npm · TanStack DB 0.6 announcement · ElectricSQL + TanStack DB · TanStack Store Letzte Aktualisierung: 2026-09-18 · Changelog

TL;DR: TanStack DB (@tanstack/db, Beta, ~3M wöchentliche Downloads) ist ein reaktiver Client-Store, der Live-Queries über Ihrer bestehenden API in unter 1ms ausführt. Collections + Live-Queries + Optimistic Mutations = das Pattern für Dashboards, Kanbans und alle UIs, bei denen sich Schreibvorgänge sofort anfühlen sollten.


Warum klassisches State Management bei Dashboard-Größenordnungen versagt

Das mentale Modell für die meisten React-Apps lautet: Schreiben → API-Aufruf → Refetch → Re-Render. Für eine einfache App funktioniert das einwandfrei.

Bei einem Dashboard mit 8 Filtern, 4 Zusammenfassungs-Panels und einer Datentabelle löst eine Filteränderung 8 API-Aufrufe aus. Der Nutzer sieht 8 Spinner. Die Daten kommen gestaffelt an. Manche Panels rendern, bevor andere fertig sind. Das Layout verschiebt sich, während jedes Panel sich füllt.

Sie versuchen optimistic Updates. TanStack Querys onMutate + onError Rollback-Pattern funktioniert für eine Mutation nach der anderen. Für ein Dashboard, bei dem eine Aktion drei zusammenhängende Ressourcen aktualisiert – Bestellungen, Umsatz und Inventar – benötigen Sie drei separate optimistic Update-Flows, die alle konsistent bleiben, wenn einer fehlschlägt. Genau hier wird onMutate/onError/onSettled zu einem 60-Zeilen-Knäuel aus gemeinsamem Rollback-State.

TanStack DB ist die Antwort des TanStack-Teams. Es sitzt vor Ihrer bestehenden REST- oder GraphQL-API, hält Daten in typisierten Collections und führt reaktive Queries aus, die inkrementell neu berechnet werden – nicht durch erneutes Ausführen der gesamten Query, sondern durch Anwenden nur der geänderten Zeilen. Das Update-Ripple durch eine Collection mit 100.000 Zeilen dauert auf einem M1-Chip etwa 0,7ms.


Die drei Grundbausteine: Collections, Live-Queries und Mutations

TanStack DB hat drei bewegliche Teile. Sobald Sie alle drei haben, erschließt sich das gesamte Modell.

Collections: Typisierte Daten-Spiegel

Eine Collection ist ein typisiertes Set von Objekten, das von einer Datenquelle gestützt wird. Die häufigste Datenquelle ist eine TanStack Query queryFn – Ihre bestehende Fetch-Logik wird direkt eingesetzt:

typescript
import { createCollection } from '@tanstack/react-db'
import { queryCollectionOptions } from '@tanstack/query-db-collection'

const ordersCollection = createCollection(
  queryCollectionOptions({
    queryKey: ['orders'],
    queryFn: () => fetch('/api/orders').then(r => r.json()),
    getKey: (order) => order.id,
    onUpdate: async ({ transaction }) => {
      const updates = transaction.mutations.map(({ key, changes }) => ({
        id: key,
        ...changes,
      }))
      await fetch('/api/orders/batch', {
        method: 'PATCH',
        body: JSON.stringify(updates),
      })
    },
  }),
)

getKey ist der eindeutige Identifier. onUpdate ist der Sync-Handler – er wird ausgelöst, wenn sich der lokale Store ändert, und sendet Mutationen an Ihre API. Da die Collection TanStack Query umschließt, erhalten Sie stale-time, Background-Refetch und das gesamte Query-Management, das Sie bereits haben.

TanStack DB 0.6 (März 2026) fügte SQLite-gestützte Persistenz über das OPFS (Origin Private File System) des Browsers hinzu. Das bedeutet: Collections überleben Seitenaktualisierungen ohne Netzwerk-Round-Trip. Für Apps, die echte Offline-First-Funktionalität benötigen, schließt dies die Lücke zwischen In-Memory-Reaktivität und persistentem lokalem State.

Live-Queries: Sub-Millisekunden-reaktive Lesevorgänge

Eine Live-Query liest aus einer oder mehreren Collections. Sie wird inkrementell neu ausgeführt, wenn sich zugrunde liegende Daten ändern – nicht durch erneutes Ausführen der vollständigen Query, sondern durch Anwenden nur des Deltas.

typescript
import { useLiveQuery, eq } from '@tanstack/react-db'

// Live-Query: offene Bestellungen, neueste zuerst
const { data: openOrders } = useLiveQuery((q) =>
  q
    .from({ order: ordersCollection })
    .where(({ order }) => eq(order.status, 'open'))
    .orderBy(({ order }) => order.createdAt, 'desc')
    .select(({ order }) => ({
      id: order.id,
      total: order.total,
      customer: order.customerName,
      createdAt: order.createdAt,
    })),
)

// Alle 8 Dashboard-Panels aktualisieren in < 1ms, wenn sich dies ändert:
const { data: revenue } = useLiveQuery((q) =>
  q
    .from({ order: ordersCollection })
    .where(({ order }) => eq(order.status, 'settled'))
    .select(({ order }) => ({
      total: order.total,
      currency: order.currency,
    })),
)

Die Performance-Aussage ist spezifisch: Gemäß der TanStack DB 0.6 Ankündigung dauert das Aktualisieren einer Zeile in einer sortierten Collection mit 100.000 Einträgen auf einem M1 Pro etwa 0,7ms. Die Kosten skalieren mit der Größe der Änderung, nicht mit der Größe der Daten.

Cross-Collection-Joins werden unterstützt:

typescript
const { data: orderItems } = useLiveQuery((q) =>
  q
    .from({ order: ordersCollection, item: itemsCollection })
    .where(({ order, item }) => eq(order.id, item.orderId))
    .select(({ order, item }) => ({
      orderId: order.id,
      total: order.total,
      itemCount: item.count,
    })),
)

Mutations: Optimistic Updates mit automatischem Rollback

Die Mutation ist dort, wo das sofortige Gefühl herkommt. Rufen Sie die Update-Methode auf der Collection auf – der lokale Store ändert sich sofort und der onUpdate-Handler löst im Hintergrund aus:

typescript
// Optimistic: Das UI aktualisiert sich, bevor der API-Aufruf erfolgt
ordersCollection.update(orderId, (draft) => {
  draft.status = 'cancelled'
  draft.cancelledAt = Date.now()
})

Wenn der API-Aufruf fehlschlägt – Netzwerkfehler, 500, Konflikt – führt TanStack DB automatisch ein Rollback durch. Keine manuelle Rollback-Logik. Kein setOptimisticUpdate / revertOptimisticUpdate-Tanz.

Für mehrstufige Flows mit Abhängigkeiten bietet createOptimisticAction einen transaktionalen Wrapper:

typescript
const { execute } = createOptimisticAction(async () => {
  await ordersCollection.update(orderId, (d) => { d.status = 'processing' })
  await paymentsCollection.insert({ orderId, amount: orderTotal })
  await inventoryCollection.update(itemId, (d) => { d.reserved = true })
})

await execute()
// Wenn ein Schritt fehlschlägt: vollständiges Rollback

Die drei Sync-Modi

TanStack DB bietet drei Datenlade-Strategien. Die Wahl bestimmt Ihr initiales Ladeverhalten:

ModusVerhaltenAm besten für
Eager (Standard)Lädt alle Datensätze bei InitialisierungKleine Datensätze < 50.000 Zeilen
On-demandLädt nur, was Queries anfordernGroße Datensätze, selektives Laden
ProgressiveSchneller First Paint + Background-Voll-SyncApps, die sofortiges UI + vollständige Daten benötigen

Für ein Dashboard mit 50.000 Bestellungen und 5 Filterpanels bedeutet der On-demand-Modus, dass jedes Panel nur sein gefiltertes Subset beim ersten Paint lädt. Progressive Modus zeigt sofort die Top-100-Ergebnisse, während der vollständige Datensatz im Hintergrund synchronisiert wird.

typescript
const ordersCollection = createCollection(
  queryCollectionOptions({
    queryKey: ['orders'],
    queryFn: fetchOrders,
    getKey: (o) => o.id,
    syncMode: 'progressive', // Schneller First Paint, Voll-Sync im Hintergrund
  }),
)

TanStack Query + TanStack DB: Wo beide ihren Platz haben

TanStack DB ersetzt TanStack Query nicht. Die offiziellen Docs sind explizit: „TanStack DB requires @tanstack/react-query." Sie sind Partner, keine Rivalen.

Das mentale Modell ist geschichtet:

  • TanStack Query verwaltet asynchronen Server-State: Fetching, Caching, Background-Refetching, Deduplizierung. Der Server ist die Quelle der Wahrheit.
  • TanStack DB verwaltet lokalen reaktiven State: Collections, Live-Queries, Optimistic Mutations. Der lokale Store ist ein schneller Spiegel des Servers.

Die Integration erfolgt durch queryCollectionOptions – die Collection nutzt TanStack Query als Transport. Die queryClient-Option verbindet die Collection mit Ihrem bestehenden TanStack Query-Setup:

typescript
import { createCollection } from '@tanstack/react-db'
import { queryCollectionOptions } from '@tanstack/query-db-collection'

const ordersCollection = createCollection(
  queryCollectionOptions({
    queryKey: ['orders'],
    queryFn: fetchOrders,
    queryClient, // ← verbindet mit Ihrem TanStack Query-Client
    getKey: (o) => o.id,
  }),
)

Wenn Sie bereits TanStack Query verwenden, beträgt die Migrationskosten für den Einsatz von TanStack DB eine Collection nach der anderen. Sie müssen nicht alles auf einmal umschreiben.


Wann TanStack DB das falsche Tool ist

TanStack DB verdient seinen Platz bei Dashboards, Kanbans und allen UIs mit abgeleiteten Datenansichten, die nach Schreibvorgängen konsistent bleiben müssen. Es ist die falsche Wahl, wenn:

  • Einfaches Fetch-and-Render: Eine Liste, keine Filter, keine abgeleiteten Ansichten. TanStack Query allein ist ausreichend und einfacher.
  • Echtes Offline-First mit Sync-Protokoll: TanStack DB ist standardmäßig In-Memory (v0.6 fügt SQLite-Persistenz hinzu, aber kein eingebautes Sync-Protokoll). Für Apps, die ElectricSQL- oder Replicache-Style bidirektionalen Sync benötigen, greifen Sie direkt zu diesen.
  • GraphQL mit normalisiertem Cache: Apollo Client und urql haben ihre eigenen normalisierten Caches. TanStack DB ist für REST- und tRPC-Backends gedacht.

TanStack DB vs. die Alternativen

FeatureTanStack DBRxDBTanStack Query allein
Lokale Query-Engine✅ Differential Dataflow✅ IndexedDB❌
Funktioniert mit bestehender REST API✅❌ (benötigt Adapter)✅
Optimistic Mutations mit Rollback✅ Automatisch✅ Manuell✅ Manuell
Sub-Millisekunden-reaktive Updates✅Teilweise❌
TanStack-Ökosystem-Integration✅ Nativ❌✅
Bundle-Größe~5KB Core~50KB+N/V
ReifegradBetaStabilStabil

RxDB ist eine vollständige Local-First-Datenbank mit IndexedDB als Basis. TanStack DB ist eine reaktive Query-Schicht, die mit Ihrer bestehenden API funktioniert – kein neues Backend erforderlich. Für Solo-Entwickler, die bereits eine REST-API haben und Dashboards wollen, die sich sofort anfühlen, ist TanStack DB die Wahl mit weniger Reibung.


Der Observable State Bonus

Jede TanStack DB Collection exponiert eine TanStack Store-Instanz. Das bedeutet, Sie können Collection-State reaktiv in Komponenten lesen, die die Hook-API nicht nutzen:

typescript
import { useStore } from '@tanstack/react-store'

function OrderCountBadge() {
  const count = useStore(ordersCollection.store, (state) =>
    state.items.filter(i => i.status === 'open').length,
  )

  return count > 0 ? <Badge>{count}</Badge> : null
}

Der store ist dieselbe Observable-Primitive, die TanStack Store antreibt. Jeder UI-State, der von Collection-Daten abhängt, kann direkt daraus lesen – kein zusätzliches useState oder Prop-Drilling erforderlich.

TanStack DB 0.6 fügte virtuelle Props hinzu, die Sync-Metadaten als abfragbare Felder exponieren: $synced (vom Server bestätigt oder noch optimistisch), $origin (lokale Änderung oder von Upstream-Sync) und $key (der Collection-Key). Diese ermöglichen Outbox-Ansichten – Benutzern anzeigen, welche Nachrichten noch ausstehen – ohne zusätzliches State-Management.


Weiterführende Lektüre: Tanstack Store Vs Zustand Vs Redux 2026 · Clerk Pricing Deep Dive What 10K Mau Actually Costs Your Saas · Tanstack Ship For Agencies Delivering Client Saas Projects On A Fixed

Meine Produktions-Checkliste

Bevor Sie TanStack DB zu einem Projekt hinzufügen:

  • Beginnen Sie mit einer Collection. Wählen Sie eine Liste mit Filtern oder abgeleiteten Ansichten. Migrieren Sie diese zuerst. Messen Sie vorher/nachher.
  • Wählen Sie den richtigen Sync-Modus. Eager für <50.000 Zeilen. On-demand für große Tabellen. Progressive für Dashboards, die sowohl schnellen First Paint als auch vollständige Daten benötigen.
  • Verdrahten Sie den onUpdate-Handler korrekt. Das Rollback funktioniert nur, wenn onUpdate der einzelne Punkt ist, der mit Ihrer API synchronisiert. Wenn Sie ihn mit einem direkten Fetch umgehen, weiß DB nichts von der Änderung.
  • Testen Sie das Rollback. Lösen Sie eine Mutation aus, lassen Sie die API einen 500er zurückgeben, und bestätigen Sie, dass sich das UI ohne jeglichen manuellen Code zurückgesetzt hat.
  • Collectionn Sie nicht über. Eine große, alles umfassende Collection besiegt das inkrementelle Update-Modell. Trennen Sie Collections nach Domänenmodell, nutzen Sie Joins für Cross-Collection-Queries.
  • Beobachten Sie das Bundle. TanStack DB Core ist ~5KB. TanStack Query fügt ~15KB hinzu. TanStack Store fügt ~3KB hinzu. Gesamt sind das ~23KB – vertretbar für ein Dashboard, nicht für eine Landing Page.

TanStack DB ist heute in TanStack Ship als Teil des optionalen Data-Layer-Add-ons verfügbar. Erfahren Sie, wie es in den vollständigen TanStack-Ökosystem-Vergleich und die Feature-für-Feature-Aufschlüsselung passt.