Loading theme preference
Ilia Bukin
← Back to blog

TanStack Table v9 is here: a rewritten core, Store-backed state, and 10 framework adapters

Aug 21, 2026
typescript
react
tanstack
frontend
open-source

TanStack Table v9 is stable. Announced on August 4, 2026, it caps more than two years of work on the headless data-grid library. The headless rendering model you already know is still there, but almost everything underneath was rebuilt: a tree-shakable plugin architecture, state backed by TanStack Store, a rewrite of every framework adapter's reactivity layer, and a handful of new features on top.

TanStack Table is the library behind React Table and its sibling adapters, and one of the more used headless table options in the JS ecosystem, sitting at 28.4k stars on GitHub. V9 is a good point to see where the project has gone.

Ten adapters, each talking to the core on its own terms

The biggest architectural change is that table state now runs on TanStack Store, whose fine-grained reactivity is built on the alien-signals architecture. Because the core no longer inherits assumptions from React, each adapter can connect to its own framework's native reactive model. That matters most for signal-based frameworks, where table atoms now hook into signals, refs, runes, and tracked values more directly.

The release lands with ten framework adapters plus the framework-agnostic @tanstack/table-core:

  • React (18+), including React Compiler support
  • Preact (10+)
  • Vue (3.2+)
  • Solid (1.3 through the latest 1.x)
  • Svelte (5+, using runes)
  • Angular (19+)
  • Lit (3.1+)
  • Alpine (3)
  • Ember (5.8+)
  • Octane (0.1)

Solid 2 is not supported yet, but the maintainers plan to support it in Table V10.

Working with TanStack Store also changed how you read and control state. You can still use the familiar state and on[State]Change options, or hand individual slices to external writable atoms when a table needs to share ownership with the rest of the app.

A plugin system that docks into your bundle

Features in Table v9 are explicit, modular, and tree-shakeable. A table that only registers sorting does not ship filtering, pagination, grouping, or the rest of the built-in set. Row-model factories and registered filter, sort, and aggregation functions are defined alongside features with tableFeatures(), so unused processing code can be dropped too. Custom features use this same system, which the maintainers say gives your own plugins the same typed access to state, options, defaults, and APIs as the features maintained in the core.

A table that only needs client-side pagination can declare exactly that:

import {
  createPaginatedRowModel,
  rowPaginationFeature,
  tableFeatures,
  useTable,
} from '@tanstack/react-table'

const features = tableFeatures({
  rowPaginationFeature,
  paginatedRowModel: createPaginatedRowModel(), // Only if client-side pagination is needed
})

const table = useTable({
  features,
  columns,
  data,
})

No other features get included unless you add them. The announcement argues this should make the average table in an application smaller than it was in v8, even though the total package grew from 14 kB to 25 kB at the time of writing.

Two helpers support building a table system across a whole product rather than configuring one table at a time. tableOptions() composes reusable features, row models, functions, and defaults while preserving type inference, and createTableHook() extends that into an app-specific table hook or factory with conventions already bound.

Sharper types

The type work is worth a closer look because it is part of why v9 is harder to upgrade but rewarding once done. Table, column, and filter metadata can now be typed per table instead of requiring global declaration merging. The type system also understands which features a table has registered, so feature APIs only exist when they are actually available and feature prerequisites can be validated before runtime, not just after something breaks.

Faster and lighter at larger scales

The performance story comes from reused prototypes for row, column, cell, and header APIs instead of recreating the same methods for every object instance. In one-million-row, eight-column paginated benchmarks, v9 used up to 86% less retained JavaScript heap than v8, dropping from about 2.71 GB to about 380 MB across the tested cases.

For processing time, the maintained benchmarks compare equivalent client-side row-model operations. At 20,000 rows and above, v9 reduced average processing time by 79% for the core row model (3.9x total-time speedup), 52% for grouping and aggregation, 37% for sorting, and 34% for filtering. Pipelining categories were already under 5 ms in both versions, so pagination benchmarks had nothing to measure.

New features that were waiting on the architecture

Cell selection is new, including rectangular ranges, drag selection, Shift extension, and multiple disjoint ranges. Cell spanning now works across rows and columns, with span-aware selection and computed header row spans for complex header layouts. Existing features were upgraded too: columns can define multiple aggregations, row selection supports Shift range selection, and column resizing was expanded and optimized. Two new APIs round it out: table.getMaxSubRowDepth() and row.getDisplayIndex().

Migration and what is next

Each adapter has a dedicated migration guide, or a quick start for the ones without one. There is also a practical detail for people using coding agents: since v9, each adapter package ships TanStack Intent skills, loaded with npx @tanstack/intent@latest install, so an agent gets guidance matched to the installed version of the table package.

V9 is meant to be a foundation rather than the end of the line. The announcement frames the tree-shakable plugin core as the base for everything that follows, and it names Solid 2 support, full pivoting, and advanced filter expressions as candidates. The maintainers note v8 and v9 came more than four years apart, and they do not expect the next major to take that long again.