Recommended Free Tools
Keep the million sales records in your backend, and have React DataGrid request only the rows needed for the current page or scroll range. The backend—not the browser—must apply sorting and filtering across the full dataset. Grid virtualization reduces the number of cells rendered in the page; it does not replace server-side querying.
This example uses MUI X Data Grid as a documented implementation pattern. “React DataGrid” does not identify a specific grid vendor, so check the data-loading features and API for the library and version you choose.
As an Amazon Associate I earn from qualifying purchases.
What the dashboard needs to do
Treat the grid as a view over a queryable sales dataset, not as a container for the entire dataset. A user changes a page, sort, or filter; the grid sends that query state to your API; the server validates it, queries the full dataset, and returns the requested rows and count information when available.
That division matters because client-side sorting or filtering on a partial page sees only the rows already loaded. To make results represent the million-row dataset, pagination, sorting, and filtering need to be handled together by the server. MUI describes this pairing in its server-side pagination documentation.
#1 Best Overall
- Server-side data loading controls how much data the browser fetches and processes.
- DOM virtualization controls how many rows and columns the grid mounts for display.
They solve different problems and are most useful together.
Design the row and query contract
Give every sales row a stable identifier
Choose a unique, stable ID for each record and expose it consistently in every response. Define the fields the dashboard needs—for example, an order ID, order date, customer, region, product, quantity, and revenue—and decide which fields users can sort or filter. This is an illustrative schema, not a required set of sales fields.
Make the API accept explicit query state
Define an endpoint that receives a page or range request along with the active sort and filter models. If the grid needs a total row count to display page controls or progress, return that count as well. The exact parameter names and response shape are your application’s contract; for example:
GET /api/sales?page=0&pageSize=50&sort=orderDate:desc&filter=region:eq:west
A response might contain the requested rows and a total count:
{
"rows": [
{ "id": "order-1042", "orderDate": "2026-09-18", "region": "West", "revenue": 245.50 }
],
"rowCount": 1000000
}
The values above are examples only; the count is not a performance claim or a measured dataset size.
Validate query requests on the server
Do not let a client-provided field name or operator become an unrestricted database instruction. Maintain an allowlist of sortable and filterable fields and supported operators, validate page or range bounds, and reject or safely handle unsupported requests. Apply the filters and sort to the full server-side dataset before selecting the requested page or range.
Return only the requested rows rather than transferring the full dataset and using client-side pagination. The server can also return count information where it is available and useful to the chosen navigation model.
Connect the grid to the API
Use a Data Source or explicit server modes
MUI X documents two related pieces of the pattern: server-side sorting, filtering, and pagination require corresponding request handling, and its Data Source can centralize row fetching. With a Data Source, the grid calls getRows() as query models change and caches fetched data by default. See the MUI X server-side data documentation for the API and configuration supported by your installed version.
Rank #3
At a high level, the integration should pass the grid’s current pagination or range, sort model, and filter model to your endpoint, then translate the response back into the shape the grid expects. If you are not using a Data Source, configure the grid’s server-side modes for the operations you handle and trigger a request when those models change. Do not enable client-side sorting or filtering on a partial result set and expect it to describe the complete dataset.
async function getRows(params) {
const response = await fetch(makeSalesUrl({
pageOrRange: params.paginationModel,
sort: params.sortModel,
filter: params.filterModel
}));
if (!response.ok) throw new Error("Could not load sales rows");
return response.json();
}
makeSalesUrl represents application code that serializes the grid state into the API contract you defined; it is not a built-in MUI function. Map only supported fields and operators, and keep the server’s validation authoritative.
Keep changing requests in the right order
Users can change filters or sorting while a previous request is still in flight. Ensure that an older response cannot replace the result for the latest query—for example, by cancelling obsolete requests or checking that a response still matches the current query state before applying it. Decide when the grid’s cached rows should be invalidated based on how fresh the dashboard needs to be. MUI documents Data Source caching and request reuse, but freshness and invalidation policy depend on the application.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Show a loading state while a request is pending and an actionable error state if it fails. If a filter change makes the current page invalid, reset or adjust the page as part of the query-state transition so the grid does not keep requesting an empty, out-of-range result.
Rank #4
Choose how users move through the results
Page-based pagination
Use pages when analysts need explicit page controls and the backend can provide a usable total count. Each request specifies a page and page size, which makes the relationship between the controls and returned rows straightforward. The server must still apply active filters and sorting across the dataset before returning that page.
Cursor pagination
Use a cursor when fetching the next result depends on where the previous request ended. This can fit sequential browsing, but it does not naturally support arbitrary jumps to a numbered page. Your API and UI need to carry the cursor between requests.
Infinite loading
Use continuous loading when the interaction is built around scrolling rather than explicit page selection. The searched MUI documentation says server-side infinite loading is available in v8 and later; confirm support and configuration for the specific grid version you deploy in the MUI X server-side data documentation.
Choose based on how analysts navigate, whether the backend can supply a total count, and the cost and complexity of the query strategy. A grid’s ability to render a scrolling viewport does not mean users can scroll through an unlimited pixel height: MUI X v8 cites browser scroll-container limits of 17.5 million pixels in Firefox and 33.5 million pixels in Chrome, Edge, and Safari in its virtualization documentation. Those are cited browser limits, not speed measurements or a recommendation for how many records people should browse at once.
Best Value
Use virtualization for rendering, not data access
Virtualization mounts only the rows and columns needed around the visible area, reducing DOM work as users scroll. It does not fetch missing records, apply a filter to records the browser has not loaded, or make client-side sorting over a partial page complete.
MUI X v8 documents rowBufferPx as a rendering hint, not a guarantee that a fixed number of extra rows will always be rendered. Its documentation also says row virtualization does not work with autoHeight. Test the actual viewport, column setup, and grid configuration you plan to ship rather than assuming virtualization alone solves large-data performance.
Build and verify the dashboard in stages
- Define the sales row ID and supported operations. Record which fields can be sorted or filtered and which operators the API accepts.
- Implement and validate the query endpoint. Have it accept the chosen page or range plus sort and filter state, query the full dataset, and return only the requested rows with count metadata when available.
- Connect the grid’s request lifecycle. Use a Data Source or explicit server modes to send each changed query state to the endpoint and map the response into the grid.
- Add request-state handling. Display loading and error states, prevent stale responses from replacing newer results, and define cache invalidation for the dashboard’s freshness needs.
- Test representative queries and scrolling against the real backend. Exercise combinations of filters, sorting, page or range changes, and rapid user changes. Profile the actual queries and rendering behavior with realistic data.
MUI’s server-side data tutorial demonstrates a full-stack example using an Express endpoint with page/page-size pagination, sorting, and filtering. Treat it as a starting pattern: multi-column sorting, advanced filter operators, cursor pagination, and other operations still need the corresponding backend implementation when your dashboard requires them.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Set performance expectations with measurements
A million-row dataset is a scale requirement, not a guaranteed performance result. The cited MUI documentation establishes implementation features and browser scroll-container limits, but it does not establish a response time, frame rate, or universally supported row count for a million-row React sales dashboard.
Measure representative backend queries and scrolling behavior with the real schema, realistic data distribution, and the filters analysts will use. Query cost depends on the backend and workload, so validate that the server can satisfy the chosen navigation and filtering pattern before treating the dashboard as ready.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




