Gerson

Gerson

Passionate developer specializing in web development, cloud architecture, and system design.

TypeScriptReactNext.jsPythonFastAPISQLNode.jsAWS

TanStack DB: Sub-Millisecond Live Queries in the Browser

TanStack DB adds a reactive client store on top of TanStack Query, using differential dataflow to update query results incrementally. The payoff is live queries that stay fast even over 100k rows.

Gersonhttps://tanstack.com/db/latest
Database tables on a screen representing a client-side data store

If you have ever kept a large list in client state and re-run a filter, sort, or join on every keystroke, you have felt the cliff: it is fine at 100 rows and janky at 10,000. TanStack DB — the newest member of the TanStack family, built on top of TanStack Query — is aimed squarely at that problem. Its headline trick is differential dataflow, which lets a live query update incrementally instead of recomputing from scratch, so complex queries stay fast at sizes that would normally drop frames.

What differential dataflow buys you

A normal derived value recomputes entirely when its input changes: change one row in a sorted, filtered list of 100,000 and a naive approach re-filters and re-sorts all 100,000. Differential dataflow instead computes only the delta — the effect of that one changed row on the result. TanStack DB implements this with d2ts, a TypeScript differential-dataflow engine, and the numbers are the point: updating a single row in a sorted 100k-item collection lands in well under a millisecond. Your query result stays live, and the work is proportional to what changed, not to how much data exists.

Collections and live queries

The two concepts are collections (typed sets of data, backed by a source) and live queries (declarative queries over collections that stay subscribed). A collection can be local-only, backed by a TanStack Query fetch against your REST or GraphQL API, or wired to a sync engine like ElectricSQL for real-time data. You query it with a builder that will look familiar to anyone who has used an ORM.

collections.ts — define a collection

import { createCollection } from "@tanstack/db";
import { queryCollectionOptions } from "@tanstack/query-db-collection";

// backed by a TanStack Query fetch; kept reactive by TanStack DB
export const todoCollection = createCollection(
  queryCollectionOptions({
    queryKey: ["todos"],
    queryFn: () => fetch("/api/todos").then((r) => r.json()),
    getKey: (todo) => todo.id,
  }),
);

Now the interesting part — a live query in a component. It re-renders only when its specific result changes, and the recompute is incremental.

TodoList.tsx — a live query with a filter

import { useLiveQuery } from "@tanstack/react-db";

function TodoList() {
  const { data: activeTodos } = useLiveQuery((q) =>
    q
      .from({ todo: todoCollection })
      .where(({ todo }) => todo.completed === false)
      .orderBy(({ todo }) => todo.createdAt, "desc"),
  );

  return activeTodos.map((t) => <TodoRow key={t.id} todo={t} />);
}

You can join across collections, aggregate, and filter, and each of those operators is incremental — a change propagates through the dataflow graph touching only the affected rows.

How it relates to TanStack Query

TanStack DB does not replace Query — it sits on top of it. Query still handles fetching, caching, and server-state lifecycle; DB adds the reactive, in-memory query layer over the top so your components read from live collections instead of re-deriving state themselves. If you already lean on Query, adopting DB is additive rather than a migration.

When it earns its place

Reach for TanStack DB when the client holds enough data that re-deriving views is a real cost — think a data grid you filter and sort interactively, a board with thousands of cards, or anything with cross-entity joins computed in the browser. For a handful of rows, plain Query plus a memoized filter is simpler and fine. The moment your derived-state logic starts showing up in a flame graph, differential dataflow is the tool that makes it disappear. It is in beta, so pin versions, but the core idea is proven and the ergonomics fit the TanStack tools you likely already use.