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
87%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
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).
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.
| v8 | v9 |
|---|---|
createSolidTable(options) | createTable({ ...options, features }) |
| Every feature bundled | Register used *Feature objects with tableFeatures() |
getCoreRowModel() option | Remove 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, aggregationFns | sortFns, 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.
| v8 | v9 |
|---|---|
table.getState() | table.atoms.<slice>.get() in tracked scopes, or broad table.store.get() |
Top-level onStateChange | Per-slice callbacks or table.store.subscribe() |
| Eager signal values in options | Getters for reactive data and controlled state slices |
| Whole-state rendering | Narrow 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.
flexRender(def, context) with <FlexRender header={header} /> or <table.FlexRender cell={cell} />.tableOptions() for typed reusable option fragments.createTableHook({ features, ...defaults }) for repeated conventions; it returns helpers such as createAppTable and createAppColumnHelper.this when extracted and are absent from object spread, Object.keys, and JSON. Table-instance methods are not affected.| v8 | v9 |
|---|---|
createColumnHelper<Person>() | createColumnHelper<typeof features, Person>() |
| Plain nested column arrays | columnHelper.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 augmentation | filterFns, sortFns, aggregationFns, and filterMeta slots |
RowData = unknown | Record or array row data |
Infer with typeof features; use StockFeatures only when deliberately typing stockFeatures.
| v8 / pre-beta.38 pinning | v9 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.
| v8 | v9 |
|---|---|
Table enablePinning | enableColumnPinning plus enableRowPinning; column-level option remains |
| Combined sizing/resizing | columnSizingFeature; add columnResizingFeature for interaction |
columnSizingInfo / onColumnSizingInfoChange | columnResizing / onColumnResizingChange |
setColumnSizingInfo() | setColumnResizing() |
sortingFn / sortingFns | sortFn / sortFns |
getSortingFn() / getAutoSortingFn() | getSortFn() / getAutoSortFn() |
SortingFn / SortingFns | SortFn / 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.
createSolidTable with createTable and inventory used features, processing, state, and APIs.tableFeatures() in prerequisite order; remove getCoreRowModel and old/early-beta row-model placement.typeof features; migrate meta and function augmentation to per-feature slots where appropriate.data and controlled state; replace getState() and onStateChange.tableOptions, table.Subscribe, or createTableHook only where composition or fine-grained rendering calls for them.stockFeatures when production tree-shaking matters.getCoreRowModel; move all eight optional row models into tableFeatures.filterFns, sortFns, aggregationFns, and filterMeta into feature slots.table.getState() and onStateChange with tracked atom/store reads, per-slice callbacks, subscriptions, or external atoms.columns(), StockFeatures, meta/registry slots, and RowData.createTable({ data: data() }) and freezing the initial array instead of providing a getter.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.
9e523bc
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.