You've seen data tables freeze browsers when loading real datasets. What starts as a simple list of 200 records becomes unusable at 10,000, forcing users to wait through sluggish filters and unresponsive scrolling.
The DOM wasn't designed for massive datasets, but your applications demand them. React's reconciliation struggles with thousands of table rows, while users expect Excel-like performance from web interfaces.
Modern data grid libraries solve this through virtualization and optimized rendering, each with different trade-offs between bundle size, features, and performance limits. You'll learn to choose between lightweight, flexible solutions and full-featured enterprise grids based on your specific dataset size and feature requirements.
In Brief:
- Table performance hits predictable walls at 1,000 and 10,000+ row thresholds where different React solutions excel or fail completely
- TanStack Table provides lightweight flexibility for custom designs, while AG Grid delivers enterprise features with proven large-dataset performance
- Virtualization becomes mandatory above 1,000 rows, and choosing the wrong approach costs weeks of refactoring when requirements change
- Decision framework based on dataset size, feature complexity, and team constraints prevents costly mid-project pivots
What is React Table?
React Table is a lightweight, fast, and extensible data grid library for React applications that provides hooks and utilities for building flexible table interfaces. It's a headless library, meaning it provides the logic and state management for tables without prescribing any specific UI or styling.
React Table has since evolved into TanStack Table, which is framework-agnostic and supports multiple frameworks beyond just React.
Unlike traditional table components that come with pre-built UI, TanStack Table handles sorting, filtering, pagination, and row selection while leaving all visual presentation decisions to developers.
The headless approach means you get Tables in React with powerful functionality without being locked into specific styling or layout constraints. At roughly 9KB gzipped, it maintains a minimal footprint while supporting complex data operations through composable hooks and utilities.
Core Features of React Table
React (TanStack) Table provides comprehensive table functionality through its hook-based API. Core features include multi-column sorting with customizable sort functions, column and global filtering with extensible filter types, and built-in pagination with configurable page sizes.
The library supports row selection with single or multi-select modes, column resizing and reordering, and grouping capabilities for hierarchical data display. Advanced features include sub-row expansion, column pinning, and virtualization support for handling large datasets efficiently.
All state management happens internally but remains accessible for external control, enabling integration with URL parameters, localStorage, or global state management solutions.
Comparing React Table Solutions and Performance
React's ecosystem offers multiple data grid solutions, each with distinct performance and flexibility trade-offs.
These approaches span from lightweight composition tools to full-featured enterprise solutions, handling sorting, filtering, and pagination with different dataset scales:
- TanStack Table – headless, lightweight toolkit for flexible UIs and mid-sized datasets
- AG-Grid – feature-rich solution handling hundreds of thousands of rows with full virtualization and server-side models
- Legacy and alternative grids – options like MUI Data Grid, DevExtreme, or older React Table versions balancing familiarity with varying scalability
Library | Performance | Bundle Size | Ideal Dataset Size | Key Features | License |
---|---|---|---|---|---|
TanStack Table | Good (with virtualization) | ~9KB gzipped | Up to 10,000 rows | Sorting, filtering, pagination | MIT |
AG-Grid Community | Excellent | ~150KB gzipped | 100,000+ rows | Row/column virtualization, sorting, filtering | MIT |
AG-Grid Enterprise | Excellent | ~250KB gzipped | 100,000+ rows | Server-side models, pivoting, Excel export | Commercial |
MUI Data Grid | Good | ~100KB gzipped | Up to 50,000 rows | Virtualization, sorting, filtering | MIT basic, commercial pro |
DevExtreme | Very Good | ~200KB gzipped | Up to 75,000 rows | Advanced filtering, grouping, exports | Commercial |
React Table v7 (legacy) | Moderate | ~12KB gzipped | Up to 5,000 rows | Sorting, filtering, basic pagination | MIT |
How to Implement High-Performance Data Tables in React
Transitioning from theory to implementation requires two distinct approaches: TanStack Table handles mid-scale datasets efficiently while AG Grid manages six-figure row counts. The implementations below cover essential code, critical performance configurations, and Strapi API integration patterns.
Build Flexible Tables with TanStack
TanStack Table's headless architecture lets you build UI components from hooks while maintaining full control over rendering.
This approach optimizes performance for datasets ranging from a few thousand to ten thousand rows without unnecessary feature overhead.
Start by installing the core dependencies:
1npm install @tanstack/react-table react-window
Memoize columns and data to prevent React re-computations. Stable references provide the most significant performance improvement:
1import { useMemo } from 'react';
2import { createColumnHelper } from '@tanstack/react-table';
3
4const columnHelper = createColumnHelper();
5
6const columns = useMemo(() => [
7 columnHelper.accessor('name', { header: 'Name' }),
8 columnHelper.accessor('price', { header: 'Price' }),
9 columnHelper.accessor('stock', { header: 'In Stock' }),
10], []);
Configure the table instance with core functionality enabled:
1const table = useReactTable({
2 data,
3 columns,
4 state: { sorting, columnFilters, pagination },
5 onSortingChange: setSorting,
6 onColumnFiltersChange: setColumnFilters,
7 onPaginationChange: setPagination,
8 getCoreRowModel: getCoreRowModel(),
9 getSortedRowModel: getSortedRowModel(),
10 getFilteredRowModel: getFilteredRowModel(),
11 getPaginationRowModel: getPaginationRowModel(),
12});
Implement virtualization to render only visible rows. This technique maintains consistent memory usage regardless of dataset growth:
1import { FixedSizeList as List } from 'react-window';
2
3function VirtualTableBody() {
4 const rows = table.getRowModel().rows;
5 return (
6 <List
7 height={400}
8 itemCount={rows.length}
9 itemSize={35}
10 overscanCount={5}
11 >
12 {({ index, style }) => (
13 <div style={style}>
14 {rows[index].getVisibleCells().map(cell => cell.renderCell())}
15 </div>
16 )}
17 </List>
18 );
19}
Connect to Strapi with robust error handling:
1async function fetchPage({ pageIndex, pageSize, sorting, filters }) {
2 const params = new URLSearchParams({
3 'pagination[page]': pageIndex + 1,
4 'pagination[pageSize]': pageSize,
5 });
6
7 const res = await fetch(`/api/products?${params.toString()}`);
8 if (!res.ok) throw new Error('Failed to load data');
9 const { data, meta } = await res.json();
10 return { data, total: meta.pagination.total };
11}
The headless approach keeps your bundle lean since no CSS gets imported automatically. Scope styles with CSS Modules or Tailwind for maximum efficiency.
Scale Rows with AG-Grid's Enterprise Features
AG Grid handles massive datasets through built-in virtualization and an infinite row model that maintains predictable memory usage beyond 100,000 rows.
Performance capabilities are demonstrated in AG Grid's official benchmarks and optimization guides.
Install the required packages:
1npm install ag-grid-community ag-grid-react
Configure the grid for large datasets using the infinite row model:
1import { AgGridReact } from 'ag-grid-react';
2
3const columnDefs = [
4 { field: 'id', sortable: true },
5 { field: 'customer', sortable: true, filter: true },
6 { field: 'amount', sortable: true, filter: 'agNumberColumnFilter' },
7];
8
9const gridOptions = {
10 columnDefs,
11 rowModelType: 'infinite',
12 cacheBlockSize: 100,
13 maxBlocksInCache: 10,
14};
Implement a datasource that streams from Strapi and provides accurate row counts for pagination:
1const dataSource = {
2 getRows: async params => {
3 const { startRow, endRow, sortModel, filterModel } = params;
4
5 const pageSize = endRow - startRow;
6 const page = startRow / pageSize + 1;
7
8 const url = new URL('/api/orders', window.location.origin);
9 url.searchParams.set('pagination[page]', page);
10 url.searchParams.set('pagination[pageSize]', pageSize);
11
12 const res = await fetch(url);
13 const { data, meta } = await res.json();
14
15 params.successCallback(
16 data.map(r => r.attributes),
17 meta.pagination.total
18 );
19 },
20};
Enterprise features like row grouping, pivoting, and Excel export require only configuration changes once you add the enterprise module. Review licensing requirements in AG Grid's community versus enterprise comparison.
Optimize scrolling performance by keeping rowBuffer
low (around 2) to minimize DOM nodes. Always run production builds—AG Grid's development mode can be significantly slower for large grids. AG Grid includes multiple CSS themes that can be imported and customized for brand consistency.
With AG Grid's infinite row model and server-side operations, you can navigate hundreds of thousands of records while maintaining responsive interactions through Strapi's API layer.
Optimize Performance with Core Rendering Techniques
Rendering a grid with 100,000 rows feels effortless once you combine three proven techniques: virtualization, memoization, and disciplined data flow.
Virtualization keeps DOM nodes minimal by rendering only viewport-visible rows and columns plus a small buffer. Libraries like react-window
and react-virtualized provide the mechanics, while enterprise grids embed virtualization automatically.
This maintains constant memory usage even with massive datasets. Keep your overscan buffer small—doubling it raises memory consumption by 30% without improving user experience.
Memoization prevents unnecessary re-renders. Wrap row components in React.memo
or use useCallback
/useMemo
so unchanged props skip React's diffing cycle:
1const Row = React.memo(
2 function Row({ record }) {
3 return <div>{record.name}</div>;
4 },
5 (prev, next) => prev.record.id === next.record.id
6);
This single comparator eliminates thousands of updates during fast scrolling.
Data fetching strategy matters as much as rendering. Page or lazy-load data so you never fetch more than users can see. Combine server-side filtering and sorting with throttled queries and cached pages to keep payloads lean.
Store bulky row data inside grid components, not global state. Only propagate lightweight UI flags (page index, sort order) through Redux
or Context
.
The opposite forces wholesale re-renders whenever any row changes. Each row needs a stable key
so React doesn't destroy and recreate nodes during scrolling.
Measure your results. Use React Profiler or Chrome DevTools to sample render times and memory snapshots while scrolling. Continuous profiling reveals hidden costs like un-memoized renderers or oversized buffers.
These practices keep any data grid—TanStack Table, AG Grid, or custom solutions—responsive as your dataset scales.
How to Choose the Best React Data Grid
Select your grid based on variables such as dataset size, required features, budget, and your team's experience.
Dataset size determines your foundation. Tables under 10,000 rows run smoothly with TanStack Table paired with react-window
for virtualization—this keeps your DOM manageable and bundle size minimal. Once you cross into six-figure row counts, client-side processing hits its limits.
AG Grid handles massive datasets through row and column virtualization plus server-side operations, staying responsive past 100,000 rows according to their performance benchmarks.
Feature complexity shapes your choice. Basic sorting and filtering work in both libraries. Advanced functionality—pivot tables, grouping, Excel-style selection—requires AG Grid Enterprise. The community-vs-enterprise comparison details what you get with each tier.
TanStack Table gives you the logic for every feature but asks you to build the UI. This flexibility comes with more setup work.
Budget constraints are straightforward. TanStack Table and AG Grid Community are MIT
-licensed. AG Grid Enterprise starts at commercial pricing—the only option here with guaranteed SLAs and vendor support.
Learning curves differ significantly. TanStack Table's headless approach means more boilerplate but a compact API surface. AG Grid follows "configure-not-compose" with hundreds of props that speed up MVPs but require deeper configuration knowledge.
Match your scenario:
- Small apps with basic tables: TanStack Table plus virtualization keeps things lean with complete styling control
- Mid-size dashboards (10K-50K rows): TanStack Table works if you handle heavy operations server-side and implement proper virtualization
- Enterprise portals (100K+ rows) with pivoting, exports, and live updates: AG Grid Enterprise delivers these features out of the box with proven server-side integration
Migration stays manageable. Upgrading React Table v7 to TanStack Table v8 typically means swapping hook names.
Moving AG Grid Community to Enterprise requires a package swap and license key. Reversing course gets trickier—removing advanced features like pivots requires refactoring.
Both libraries follow predictable release cycles. AG Grid provides long-term support for enterprise clients, while TanStack evolves quickly with semver compliance and community contributions.
Match this cadence to your product lifecycle, then connect either solution to Strapi's REST or GraphQL endpoints for a backend that scales with your choice.
Power Your React Applications with the Right Data Grid
Choose your React data grid based on concrete metrics: dataset size, feature needs, budget, and team skills. For under 10,000 rows with basic sorting, TanStack Table offers lightweight flexibility. For massive datasets requiring enterprise features, AG Grid delivers proven performance at scale.
Implementation strategy is crucial—virtualization should be standard practice from the start. Strapi's API-first architecture provides the perfect backend foundation, delivering paginated, filtered data to either grid solution.