CtrlK
BlogDocsLog inGet started
Tessl Logo

migrate-v8-to-v9

Perform a complete @tanstack/solid-table v8-to-v9 migration: createTable, explicit features and row-model slots, getter-based Solid reactivity, atom state, rendering, composable tables, type helpers, and every shared API rename and semantic change. Use for migration plans, implementation, or audits.

70

Quality

87%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

Read @tanstack/table-core#migrate-v8-to-v9, getting-started, and table-state. Use this as the exhaustive Solid migration checklist. Check the installed declarations before emitting APIs for another beta.

Framework prerequisite: Solid 1.3 or newer (solid-js >=1.3).

Target architecture

import {
  createSortedRowModel,
  createTable,
  rowSortingFeature,
  tableFeatures,
} from '@tanstack/solid-table'

const features = tableFeatures({
  rowSortingFeature,
  sortedRowModel: createSortedRowModel(),
})

const table = createTable({
  features,
  columns,
  get data() {
    return data()
  },
})

Keep static features and columns outside reactive component work. Prefer explicit features as the end state; stockFeatures is a kitchen-sink migration shortcut.

Complete breaking-change map

Construction and feature registration

v8v9
createSolidTable(options)createTable({ ...options, features })
Every feature bundledRegister used *Feature objects with tableFeatures()
getCoreRowModel() optionRemove it; core is automatic
getFilteredRowModel()filteredRowModel: createFilteredRowModel()
getSortedRowModel()sortedRowModel: createSortedRowModel()
getPaginationRowModel()paginatedRowModel: createPaginatedRowModel()
getExpandedRowModel()expandedRowModel: createExpandedRowModel()
getGroupedRowModel()groupedRowModel: createGroupedRowModel()
getFacetedRowModel()facetedRowModel: createFacetedRowModel()
getFacetedMinMaxValues()facetedMinMaxValues: createFacetedMinMaxValues()
getFacetedUniqueValues()facetedUniqueValues: createFacetedUniqueValues()
Table/factory sortingFns, filterFns, aggregationFnssortFns, filterFns, aggregationFns feature slots
Early-beta rowModels: { ... }Direct named slots in tableFeatures()

In the registry slots, register individually imported built-ins (filterFn_includesString, sortFn_alphanumeric, aggregationFn_sum, and so on) under their conventional keys alongside custom functions; the full filterFns/sortFns/aggregationFns registry objects still work but bundle every built-in.

Place each prerequisite feature before its row-model slot. Stock features are cellSelectionFeature, columnFilteringFeature, globalFilteringFeature, rowSortingFeature, rowPaginationFeature, rowSelectionFeature, rowExpandingFeature, rowPinningFeature, columnPinningFeature, columnVisibilityFeature, columnOrderingFeature, columnSizingFeature, columnResizingFeature, rowAggregationFeature, columnGroupingFeature, and columnFacetingFeature. Aggregation is independent from grouping: register rowAggregationFeature for aggregation APIs and add columnGroupingFeature only for grouped rows.

Solid state and reactivity

v8v9
table.getState()table.atoms.<slice>.get() in tracked scopes, or broad table.store.get()
Top-level onStateChangePer-slice callbacks or table.store.subscribe()
Eager signal values in optionsGetters for reactive data and controlled state slices
Whole-state renderingNarrow atom reads, createMemo, or table.Subscribe
const [sorting, setSorting] = createSignal<SortingState>([])
const table = createTable({
  features,
  columns,
  get data() {
    return data()
  },
  state: {
    get sorting() {
      return sorting()
    },
  },
  onSortingChange: setSorting,
})

table.Subscribe passes atoms to its child. A Solid component child body is untracked, so read atoms inside JSX expressions or a thunk invoked by JSX:

<table.Subscribe>
  {(atoms) => <span>Page {atoms.pagination.get().pageIndex + 1}</span>}
</table.Subscribe>

Use createAtom/useSelector from @tanstack/solid-store for externally owned slices. An external atom wins over state for the same slice; do not combine ownership models accidentally.

Rendering and composition

  • Replace flexRender(def, context) with <FlexRender header={header} /> or <table.FlexRender cell={cell} />.
  • Use tableOptions() for typed reusable option fragments.
  • Use createTableHook({ features, ...defaults }) for repeated conventions; it returns helpers such as createAppTable and createAppColumnHelper.
  • Invoke row/cell/column/header methods through their instance. Prototype methods lose this when extracted and are absent from object spread, Object.keys, and JSON. Table-instance methods are not affected.

TypeScript and helper changes

v8v9
createColumnHelper<Person>()createColumnHelper<typeof features, Person>()
Plain nested column arrayscolumnHelper.columns([...]) for TValue inference
ColumnDef<TData>ColumnDef<TFeatures, TData, TValue>
Column<TData>, Row<TData>, Table<TData>Add TFeatures first
Cell<TData, TValue>Cell<TFeatures, TData, TValue>
TableMeta<TData> / ColumnMeta<TData, TValue>Add TFeatures, or use per-table tableMeta / columnMeta with metaHelper()
Global FilterFns, SortFns, AggregationFns, and FilterMeta augmentationfilterFns, sortFns, aggregationFns, and filterMeta slots
RowData = unknownRecord or array row data

Infer with typeof features; use StockFeatures only when deliberately typing stockFeatures.

Shared API and semantic changes

v8 / pre-beta.38 pinningv9 beta.38+
columnPinning.left / .right.start / .end
column.pin('left' | 'right')column.pin('start' | 'end')
getIsPinned() === 'left' | 'right''start' | 'end'
row.getLeftVisibleCells() / getRightVisibleCells()getStartVisibleCells() / getEndVisibleCells()
getLeftHeaderGroups() / getRightHeaderGroups()getStartHeaderGroups() / getEndHeaderGroups()
getLeftFooterGroups() / getRightFooterGroups()getStartFooterGroups() / getEndFooterGroups()
getLeftFlatHeaders() / getRightFlatHeaders()getStartFlatHeaders() / getEndFlatHeaders()
getLeftLeafHeaders() / getRightLeafHeaders()getStartLeafHeaders() / getEndLeafHeaders()
getLeftLeafColumns() / getRightLeafColumns()getStartLeafColumns() / getEndLeafColumns()
getLeftVisibleLeafColumns() / getRightVisibleLeafColumns()getStartVisibleLeafColumns() / getEndVisibleLeafColumns()
getLeftTotalSize() / getRightTotalSize()getStartTotalSize() / getEndTotalSize()
column.getStart('left')column.getStart('start')
column.getAfter('right')column.getAfter('end')
column.getIndex('left' | 'right')column.getIndex('start' | 'end')

Logical pinning does not implement DOM direction styling; use logical CSS insets. columnResizeDirection is unchanged.

v8v9
Table enablePinningenableColumnPinning plus enableRowPinning; column-level option remains
Combined sizing/resizingcolumnSizingFeature; add columnResizingFeature for interaction
columnSizingInfo / onColumnSizingInfoChangecolumnResizing / onColumnResizingChange
setColumnSizingInfo()setColumnResizing()
sortingFn / sortingFnssortFn / sortFns
getSortingFn() / getAutoSortingFn()getSortFn() / getAutoSortFn()
SortingFn / SortingFnsSortFn / SortFns
row._getAllCellsByColumnId()row.getAllCellsByColumnId()
table._getPinnedRows()getTopRows(), getCenterRows(), or getBottomRows()
table._getFacetedRowModel()Public faceting APIs on the relevant column/table
table._getFacetedMinMaxValues()getFacetedMinMaxValues()
table._getFacetedUniqueValues()getFacetedUniqueValues()

All other underscore-prefixed internals are removed. getIsSomeRowsSelected() and getIsSomePageRowsSelected() now mean at least one even when all are selected. Use getIsSomeRowsSelected() && !getIsAllRowsSelected() or getIsSomePageRowsSelected() && !getIsAllPageRowsSelected() for checkbox indeterminate state.

Migration procedure

  1. Replace createSolidTable with createTable and inventory used features, processing, state, and APIs.
  2. Build tableFeatures() in prerequisite order; remove getCoreRowModel and old/early-beta row-model placement.
  3. Apply all pinning, sizing, sorting, row, and selection mappings above.
  4. Update helpers/types with typeof features; migrate meta and function augmentation to per-feature slots where appropriate.
  5. Preserve Solid tracking with getters for data and controlled state; replace getState() and onStateChange.
  6. Choose internal, controlled-signal, or external-atom ownership per slice.
  7. Replace unbound row/cell/column/header methods and migrate rendering.
  8. Add tableOptions, table.Subscribe, or createTableHook only where composition or fine-grained rendering calls for them.
  9. Type-check and exercise every enabled client- and server-side flow.
  10. Audit away stockFeatures when production tree-shaking matters.

Final migration checklist

  • Replace createSolidTable with createTable and preserve reactive inputs through getters.
  • Register every used stock feature explicitly and order prerequisites before slots.
  • Remove getCoreRowModel; move all eight optional row models into tableFeatures.
  • Move filterFns, sortFns, aggregationFns, and filterMeta into feature slots.
  • Replace table.getState() and onStateChange with tracked atom/store reads, per-slice callbacks, subscriptions, or external atoms.
  • Audit Solid tracking scopes, controlled getters, atom precedence, and reset ownership.
  • Replace unbound/copied row, cell, column, and header methods.
  • Apply the complete logical pinning map and CSS changes.
  • Split pinning options and sizing/resizing; rename the resizing state, setter, and callback.
  • Apply every sorting rename and remove each listed internal API.
  • Pair some-selected with the matching all-selected predicate.
  • Update TFeatures helpers/types, columns(), StockFeatures, meta/registry slots, and RowData.
  • Migrate Solid FlexRender and use tableOptions/createTableHook only for repeated conventions.
  • Type-check and exercise every enabled client/manual feature and LTR/RTL layout flow.
  • Audit away temporary stockFeatures usage when explicit tree-shaking is intended.

Common migration failures

  • Calling createTable({ data: data() }) and freezing the initial array instead of providing a getter.
  • Leaving row models in table options or omitting their prerequisite feature.
  • Reading atoms in an untracked component child body and expecting Solid updates.
  • Supplying controlled state without getter properties or per-slice callbacks.
  • Destructuring prototype-backed object methods.
  • Updating pinning state names but not CSS and region APIs.
  • Treating changed “some selected” semantics as checkbox indeterminate state.

API discovery

Inspect node_modules/@tanstack/solid-table/dist/index.d.ts and node_modules/@tanstack/table-core/dist/index.d.ts. Compare v8 names only against the migration guide, not current main-branch assumptions.

Repository
TanStack/table
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.