Skip to content

Repository files navigation

TanStack Table Benchmark Examples

Dedicated memory and row-model operation benchmarks for similar TanStack Table v8 and v9 React examples.

Each benchmark is an independent Vite example with its own package.json, mirroring the structure of the existing TanStack examples:

  • examples/v8/virtualized-rows
  • examples/v8/virtualized-columns
  • examples/v8/paginated-rows
  • examples/v8/kitchen-sink
  • examples/v8/core-row-model
  • examples/v8/sorting-row-model
  • examples/v8/filtering-row-model
  • examples/v8/grouping-row-model
  • examples/v8/expanding-row-model
  • examples/v8/pagination-row-model
  • examples/v8/faceting-row-model
  • examples/v8/selection-row-model
  • examples/v9/virtualized-rows
  • examples/v9/virtualized-columns
  • examples/v9/paginated-rows
  • examples/v9/kitchen-sink
  • examples/v9/core-row-model
  • examples/v9/sorting-row-model
  • examples/v9/filtering-row-model
  • examples/v9/grouping-row-model
  • examples/v9/expanding-row-model
  • examples/v9/pagination-row-model
  • examples/v9/faceting-row-model
  • examples/v9/selection-row-model

Shared deterministic data, config parsing, and CSS live in shared/src.

Install

pnpm install

v9 Version Maintenance

Keep the tracked examples/v9/* examples on the latest published v9 beta before using them as the baseline for PR comparisons. Update every v9 example that depends on @tanstack/react-table and/or @tanstack/table-core, then refresh only the tracked v9 workspace importers in the lockfile:

VERSION=9.0.0-beta.21

for d in examples/v9/*; do
  if [ -f "$d/package.json" ]; then
    node -e "const p=require('./$d/package.json'); process.exit(p.dependencies?.['@tanstack/react-table'] ? 0 : 1)" &&
      (cd "$d" && npm pkg set "dependencies.@tanstack/react-table=$VERSION")
    node -e "const p=require('./$d/package.json'); process.exit(p.dependencies?.['@tanstack/table-core'] ? 0 : 1)" &&
      (cd "$d" && npm pkg set "dependencies.@tanstack/table-core=$VERSION")
  fi
done

pnpm install --lockfile-only --filter './examples/v9/**'

PR Preview Setup

To compare a table PR against the current v9 baseline, copy the tracked v9 examples to a temporary folder and install the PR preview packages into the copy. Use a unique package name for each copied example so pnpm workspace discovery does not see duplicate package names:

PR=6347
TEMP="examples/v9-pr-temp-$PR"

cp -R examples/v9 "$TEMP"

for d in "$TEMP"/*; do
  if [ -f "$d/package.json" ]; then
    name="benchmark-table-v9-pr-$PR-$(basename "$d")"
    (cd "$d" && npm pkg set "name=$name")
    (cd "$d" && npm install --force --prefer-online \
      "https://pkg.pr.new/TanStack/table/@tanstack/table-core@$PR" \
      "https://pkg.pr.new/TanStack/table/@tanstack/react-table@$PR")
  fi
done

These v9-pr-temp-* folders are intended as local benchmark fixtures. Do not treat their generated package locks, builds, or result files as part of the normal tracked benchmark baseline unless a specific comparison needs to be preserved.

Run

pnpm bench:memory

Useful flags:

pnpm bench:memory -- --iterations 5 --overscan 5

Run only one benchmark group:

pnpm bench:memory -- --benchmark rows
pnpm bench:memory -- --benchmark columns
pnpm bench:memory -- --benchmark paginated-rows
pnpm bench:memory -- --benchmark kitchen-sink

Capture beginning/end heap snapshots for the first iteration of each v8/v9/config combination:

pnpm bench:memory -- --heapSnapshots true

By default snapshots are captured only for configs with at most 10,000 estimated cells, because large browser heap snapshots can be multiple GB and impractical to create or parse locally. Adjust with:

pnpm bench:memory -- --heapSnapshots true --maxSnapshotCells 100000

Smooth scroll phases are captured only for configs with at most 1,000,000 estimated cells by default. Larger configs still record initial and instant-scroll phases, plus a smooth-scroll-skipped marker. Adjust with:

pnpm bench:memory -- --maxSmoothScrollCells 10000000

The runner builds each independent example, starts vite preview for one example at a time, opens it in a fresh Chromium context, and records:

  • JSHeapUsedSize before forced GC
  • JSHeapUsedSize after forced GC
  • memory reclaimed by forced GC
  • DOM document, node, and event listener counts
  • rendered row and cell counts for equivalence checks

It measures these phases:

Virtualized examples:

  • initial
  • instant-middle-scroll
  • instant-end-scroll
  • smooth-middle-scroll
  • smooth-end-scroll

Paginated examples:

  • initial
  • next-page
  • last-page

Results are written to results/*.json, results/*.csv, and results/*.html.

Row Model Benchmarks

Run core, filtering, sorting, grouping, expanding, pagination, faceting, and selected-row-model benchmarks:

pnpm bench:row-model

Useful flags:

pnpm bench:row-model -- --iterations 5 --warmups 0
pnpm bench:row-model -- --rowModel sorting
pnpm bench:row-model -- --rowModel filtering --scenario includesString
pnpm bench:row-model -- --rowModel grouping --scenario sum
pnpm bench:row-model -- --rowModel faceting --scenario statusUnique
pnpm bench:row-model -- --rows 1000,20000,100000,400000
pnpm bench:row-model -- --includeV9Only false
pnpm bench:row-model -- --pipeline full

The row-model runner builds the matching v8 and v9 row-model examples, starts vite preview for one example at a time, opens the app in Chromium, and calls a headless browser benchmark API exposed by the example. Each sample creates a fresh table instance and times the target getter for that scenario.

By default, --pipeline stage primes upstream row models before timing so the measurement isolates the target stage. Use --pipeline full to time the target getter from a fresh table instance without priming predecessors.

The default row-count matrix is 1,000, 20,000, 100,000, and 400,000 rows. The row-model runner ignores row counts above 400,000 to keep memory pressure from dominating the measurements. Smaller row counts are useful for smoke tests and for catching low-row-count overhead, but sub-millisecond timings can produce noisy percentages.

Row-model benchmark data is generated once from seeded Faker data into shared/generated/rowModelFlatData.json and shared/generated/rowModelTreeData.json before the runner builds examples. The flat fixture powers all non-expanding scenarios. The tree fixture powers expanding scenarios with deterministic nested subRows.

Generate the standalone fixtures manually before running a row-model example directly:

pnpm generate:row-model-data -- --rows 400000

Long runs print progress for fixture generation, example builds, preview server startup, each version, and each row-model/row-count group.

Focused row-model scenarios:

  • core: flat
  • sorting: alphanumeric, alphanumericCaseSensitive, text, textCaseSensitive, datetime, basic, each asc and desc
  • filtering: built-in v8/v9 filterFns plus v9-only filterFns when enabled
  • grouping: sum, min, max, extent, mean, median, unique, uniqueCount, count
  • expanding: collapsed, partialExpanded, allExpanded
  • pagination: firstPage10, middlePage50, lastPage100
  • faceting: statusUnique, alphanumericUnique, scoreMinMax, statusFacetedRowsWithTextFilter
  • selection: selectedCore1Percent, filteredSelected10Percent, groupedSelected10Percent

For grouping scenarios, the benchmark reads grouped aggregate values inside the timed section so the aggregation functions are actually executed. Row selection scenarios measure selected-row-model derivation only; row toggle/update interaction costs are intentionally out of scope for this runner. The grouped selected-row-model scenario currently documents a v8/v9 semantic difference: v8 derives from the grouped row model, while v9 beta.29 derives from the core row model.

Row-model benchmark results are written to results/row-model-*.json, results/row-model-*.csv, and results/row-model-*.html.

Notes

The examples intentionally use the same React, React DOM, TanStack Virtual, Vite, and deterministic data generator. The main intended variable is @tanstack/react-table v8 versus v9.

Default sample size is 5 iterations.

Default dimensions:

Rows benchmark:

  • 10 rows x 8 columns
  • 1,000 rows x 8 columns
  • 100,000 rows x 8 columns
  • 1,000,000 rows x 8 columns

Paginated rows benchmark:

  • 10 rows x 8 columns
  • 1,000 rows x 8 columns
  • 100,000 rows x 8 columns
  • 1,000,000 rows x 8 columns

Kitchen sink benchmark:

  • 10 rows x 8 columns
  • 1,000 rows x 8 columns
  • 100,000 rows x 8 columns
  • 1,000,000 rows x 8 columns

Columns benchmark:

  • 10 rows x 10 columns
  • 100 rows x 100 columns
  • 100 rows x 1,000 columns
  • 100 rows x 10,000 columns

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages