Skip to main content
Tally renders only what is on screen, runs queries where the data lives, and patches rows in place. This page explains each part and the benchmarks that guard them.

Benchmarks

tally-core ships two benchmarks. Each one fails when the mean latency of a case goes over its budget.
packages/core/src/grid/stress.bench.ts runs against 100,000 generated rows with 50 columns of every built-in type. packages/core/src/execute/executor.bench.ts runs the executor against 100,000 rows with five columns. Filter and sort, group with an aggregate, three facets and a search each stay under 250 ms. The numbers are budgets, not measurements. Run the benchmarks on your own hardware for real timings.

The stress dataset

The playground has a developer dataset at #/stress. It generates 100,000 rows with 50 columns in the browser and serves them from an in-memory array source: pinned and wide columns, enum pills, avatars, sparklines, meters, relative dates and footer aggregates. Use it to feel scrolling, sorting, grouping and filtering at that size.

Virtualization

tally-react virtualizes rows and columns with TanStack Virtual. Only the visible rows, plus six above and below, and the visible columns, plus two on each side, are in the DOM. Pinned columns and pinned rows stay mounted. The cards layout is virtualized too.

Where queries run

The grid sends each query to its data source and computes locally only what the source cannot do. Pick the source by where the rows live.
Work the grid does locally only sees loaded rows. For large tables, use a source that filters, sorts and groups on the server.
See Data sources and Pagination.

Loading

Live updates

Patches update rows in place. Under a sort, changed rows move to their new position without a reload. That is the patch 1k rows with live sort case above. See Live updates.

Rendering in React

The hooks read the engine through useSyncExternalStore. useGridState and useView take a selector, and a component re-renders only when the selected value changes.
status.tsx
Keep renderers, editors and labels stable across renders. Define them outside the component or memoize them, so cells do not re-render for nothing.