TanStack logo

Skill

client-vs-server

manage TanStack Table data pipelines

Covers Performance Data Pipeline TanStack Frontend

Description

Choose client or server ownership for filtering, grouping, sorting, expanding, and pagination in TanStack Table v9. Load for manual* flags, mixed pipelines, server counts, or deciding which dataset each row-model stage receives.

SKILL.md

This skill builds on core and table-features. Read them first for the model pipeline and plugin slots.

Setup

import {
  rowPaginationFeature,
  rowSortingFeature,
  tableFeatures,
} from '@tanstack/table-core'

export const features = tableFeatures({
  rowSortingFeature,
  rowPaginationFeature,
})
export const serverOptions = {
  manualSorting: true,
  manualPagination: true,
  rowCount: 12_450,
} as const

Core Patterns

Client owns the complete pipeline

const features = tableFeatures({
  columnFilteringFeature,
  filteredRowModel: createFilteredRowModel(),
  rowSortingFeature,
  sortedRowModel: createSortedRowModel(),
  rowPaginationFeature,
  paginatedRowModel: createPaginatedRowModel(),
})

Pass the full client dataset so each stage can process all rows.

Server owns processing

const options = {
  data: serverPage.rows,
  manualFiltering: true,
  manualSorting: true,
  manualPagination: true,
  rowCount: serverPage.total,
}

Put controlled filter, sorting, and pagination state into the request/query key.

Common Mistakes

CRITICAL Treating manual flags as requests

Wrong:

const options = { manualSorting: true, data: unsortedRows }

Correct:

const sortedPage = await fetchPage({ sorting })
const options = { manualSorting: true, data: sortedPage.rows }

manualSorting only bypasses client sorting; it never calls a backend.

Source: packages/table-core/src/features/row-sorting/rowSortingFeature.types.ts

HIGH Expecting manual pagination to slice

Wrong:

const options = { data: allRows, manualPagination: true }

Correct:

const page = await fetchPage({ pageIndex, pageSize })
const options = {
  data: page.rows,
  manualPagination: true,
  rowCount: page.rowCount,
}

Manual pagination assumes data already represents the intended page. Pass the stable page result directly. If the application deliberately performs custom local slicing instead, derive it with the framework's memo/computed primitive and keep the reference stable until its actual inputs change.

Source: docs/framework/react/guide/pagination.md#manual-server-side-pagination

HIGH Sorting only the loaded page accidentally

Wrong:

const options = {
  data: serverPage.rows,
  manualPagination: true,
  manualSorting: false,
}

Correct:

const options = {
  data: serverPage.rows,
  manualPagination: true,
  manualSorting: true,
}

Client sorting can see only loaded rows, so it cannot produce database-wide order.

Source: docs/guide/row-models.md

HIGH Recreating processed data or columns inline

Wrong:

const options = {
  data: allRows.filter(matchesFilters).slice(pageStart, pageEnd),
  columns: makeColumns(),
}

Correct:

const processedRows = pageResult.rows
const columns = sharedColumns
const options = { data: processedRows, columns }

data and columns are model inputs. Keep both references stable between meaningful changes with module constants, state, or the adapter's memo/computed primitive; otherwise Table repeatedly invalidates row and column models and some adapters can enter render loops. “Manual” describes processing ownership, not permission to derive new arrays inside table options.

Source: docs/guide/data.md

API Discovery

Inspect node_modules/@tanstack/table-core/dist/core/row-models/coreRowModelsFeature.utils.d.ts for pipeline order and each feature's .types.d.ts for its manual* contract.

© 2026 YourAI.tools. Every skill from an identity-verified publisher.

Independent catalog. Not affiliated with, endorsed by, or sponsored by Anthropic or any listed publisher. All trademarks belong to their respective owners.