UI Performance
Large financial applications often surface hundreds of thousands of rows across grids, with continuous real-time updates. The Genesis platform spreads tuning options across grids, communications, and the Data Server. This page summarises the main levers and points to the detailed references.
For a non-technical guide to help clients and business analysts agree data volume, freshness, and screen behaviour before build, see Planning data and screens for performance.
Quick decision guide
| Situation | Prefer |
|---|---|
| Modest row counts that fit comfortably in memory | Client-side datasource on Grid Pro or default Entity Manager |
| Large or unbounded tables, heavy sort/filter | Server-side datasource (AG Grid Enterprise) or Entity Manager with datasource-type="server" — see Data Server or Request Reply |
| Frequent real-time row updates in a bounded grid window | Data Server with tuned MAX_ROWS / MAX_VIEW / MOVING_VIEW |
| Infrequent updates or seconds-scale refresh via HTTP polling | Request Server with criteria-only mode where appropriate |
| CRUD screens from metadata | Entity Manager with tuned datasourceConfig |
| Read-only or custom grid UX | Grid Pro directly |
| Large dropdowns (select / combobox on reference data) | options-datasource with infinite-scroll and tuned page-size |
| Very wide Data Server grids (many columns, users hide columns) | grid-pro-genesis-datasource with request-visible-columns-only |
| Serving reference or snapshot data over HTTP from a custom endpoint | Cache and compress the response — ETag/304 plus httpCompression |
Avoid loading an entire large query into the browser when server-side row model or pagination can keep each page bounded.
Data Server or Request Reply
Choosing between a Data Server subscription and Request Reply is not only about how many rows exist in the database. Both approaches must cap how much data the browser holds; virtualisation reduces rendering cost but does not remove subscription size limits.
| Prefer Data Server | Prefer Request Reply |
|---|---|
| Rows change often and you benefit from streaming delta updates over WebSocket | Rows change rarely, or HTTP polling with a delay of a few seconds (tune pollingInterval and Connect polling) is acceptable |
A bounded live window (MAX_ROWS, MAX_VIEW, MOVING_VIEW) matches the UX | You need database-side criteria and sort on columns that are not backed by Data Server indices, and criteria-only mode applies |
For either resource type, use a server-side grid datasource when the dataset is too large to download in full. Server-side row model (SSRM) works with both Data Server queries and Request Reply resources; it is not a separate pattern that replaces Data Server for live data above a fixed row count.
Request Reply trade-off: polling is less efficient than a WebSocket Data Server stream, but it is a valid choice when refresh latency is tolerable. Point configuration to Request Server and client pollingInterval / router POLLING_FREQUENCY rather than loading the full result set client-side.
How many rows to subscribe to
There is no single row count that fits every grid. Transfer size and memory pressure depend on row count × column count × value size. The default MAX_VIEW of 1000 is a starting point, not a guarantee: a grid with hundreds of columns (as in some legacy workloads) may need a much lower cap than a narrow grid with the same row count.
Use a practical budget:
- Estimate cells in flight (subscribed rows × columns you actually send).
- Lower
MAX_ROWSandMAX_VIEWwhen columns are wide or values are large. - For “latest activity” views, prefer a moving live window (
MOVING_VIEW= true) over raisingMAX_VIEWto tens of thousands so the grid can show new rows without holding the full history in the browser.
Users often need to search across a large table without loading every row into the grid. That is solved with server-side criteria on indexed fields and UI that encourages filtering—not by subscribing to the entire dataset.
Large read-heavy grids
When the backing store may hold tens of thousands of rows (trades, orders, audit events) but each user only works with a filtered slice:
- Expose a Data Server query (or Request Reply with criteria-only where indices do not fit).
- Define indices on fields users sort and filter on.
- Use a server-side grid datasource so
CRITERIA_MATCHandORDER_BYrun on the server. - Provide explicit filter UX—Foundation Filters or Entity Manager filter configuration (
enable-filters)—and pass criteria into the grid datasource so users narrow results before scrolling. - Cap subscription size with
MAX_ROWS/MAX_VIEW; align Entity ManagerdatasourceConfig.maxRowswith the same limits.
This guidance is about preventing unbounded client subscriptions on new projects. Retrofitting an app that already streams an oversized view requires design changes (indices, filters, column reduction), not only documentation.
1. Choose how much data the browser holds
Grid datasources
- Client-side — sorting and filtering run in the browser. Suitable when the full result set is small enough to download and keep in memory. See Grid Pro datasources.
- Server-side — sort and filter are sent to the backend (
ORDER_BY,CRITERIA_MATCH); only the current window of rows is loaded. Behaviour depends on the resource type:- Data Server
query— sorting is limited to columns backed by a Data Server index. Grid Pro enables sort on columns where metadata exposes a valid index. - Request Server
requestReply— withcriteriaOnlyRequest, criteria and sorting are evaluated on the database where supported, so sortable columns are not restricted to Data Server-style indices (seesortableFieldsin resource metadata). Without criteria-only mode, the same index constraints as Data Server apply when streaming through the server-side datasource. - See server-side datasource notes.
- Data Server
grid-pro-genesis-datasource— on Data Server resources, enablerequest-visible-columns-onlywhen the grid defines many columns but users typically show a subset. The datasource sends only theFIELDSfor currently visible columns (plus the row id field for tracking), and reloads when column visibility changes. See Grid Pro genesis datasource. Has no effect on Request Server resources; use staticfieldswhere you need a fixed subset.
request-visible-columns-only requires @genesislcap/grid-pro 14.489 or later.
Entity Manager
Set datasource-type="server" to use grid-pro-server-side-datasource for the list. Use datasourceConfig to narrow what is requested:
criteriaandorderByto limit and order on the servermaxRowsto cap each fetchfieldsto omit unused columns (only applies to dataserver)pollingInterval/pollTriggerEventsonly when HTTP polling is required—prefer WebSocket subscriptions when possible
See Entity Manager and the declarative API.
Large dropdowns (select and combobox)
Grids are not the only control that can pull thousands of rows into the browser. A Select or Combobox with a slotted options-datasource loads from the same Data Server and Request Server resources as grids. Without paging, it typically fetches up to the default datasource window (on the order of hundreds of rows per request and up to the max-view cap on streams).
For long reference lists (counterparties, accounts, instruments):
- Enable
infinite-scrollonoptions-datasourceso onlypage-sizeoptions (default 20) load initially; further pages load when the user scrolls the listbox. - Set a stable
order-bywhen the resource is Request Server–backed, so offset paging stays consistent while the user scrolls. - For comboboxes, expect server-side search: infinite scroll turns on async filtering so typed input sends
CRITERIA_MATCHinstead of filtering a single page in the browser. - Keep
max-viewrealistic on Data Server–backed dropdowns; paging usesMORE_ROWSon the live subscription and cannot exceed the tracked view.
infinite-scroll on options-datasource requires @genesislcap/foundation-ui 14.489 or later.
This is often a quick win on forms that feel slow even when the main grid is already tuned.
2. Tune Data Server subscriptions
Each grid or datasource subscription is governed by Data Server DATA_LOGON parameters. These control how many rows are sent initially, how large the tracked view grows, and whether pagination is used.
| Parameter | Role |
|---|---|
MAX_ROWS | Rows per initial load and per MORE_ROWS request |
MAX_VIEW | Maximum rows tracked for the subscription; 0 allows unbounded growth for infinite scroll without pre-allocating a huge server structure |
MOVING_VIEW | When true, new real-time rows can replace oldest rows once MAX_VIEW is reached |
VIEW_NUMBER | Non-zero enables pagination mode (page replaces previous rows) |
Typical patterns:
- Fixed live window —
MAX_ROWS=MAX_VIEW,MOVING_VIEW= false so updates apply only to visible rows. - Infinite scroll — server-side datasource with pagination disabled; consider
MAX_VIEW=0for scroll growth; use grid row count in server-side infinite scroll. - Pagination —
MAX_ROWS= page size,VIEW_NUMBER≥ 1,MOVING_VIEW= false; align with grid pagination or Entity Manager grid options. On large trading and operations grids, server-side search and filter on indexed fields usually delivers a better experience than paging through an unfiltered history; treat pagination as a secondary option when users truly need to walk fixed pages of a already-narrowed result set.
Full behaviour is documented under rows and view concepts.
3. Optimise the grid UI
Even with bounded data, rendering cost matters.
- Search and filter UX — let users narrow large datasets on the server before scrolling; see Foundation Filters, Entity Manager filters, and criteria matching.
- DOM virtualisation — only visible rows and columns are in the DOM. Enabled by default on Grid Pro; see Performance.
- Request visible columns only — on Data Server–backed
grid-pro-genesis-datasource, setrequest-visible-columns-onlyso wire traffic matches displayed columns, not every field on the query. - Lightweight renderers — prefer built-in renderers; keep custom cell renderers small. See performance considerations.
- Pagination — load one page at a time when a paged UX is required; combine with virtualisation for very wide or tall pages. Prefer indexed filter fields over pagination alone for financial workloads with deep history.
4. Write queries that scale on the server
- Define indices on Data Server queries for fields users sort and filter on. Searchable filter fields should be indexed; see indices.
- Derived fields are fine for display, but filtering and sorting only scale when filterable values live on the underlying table or view (or are persisted there). Avoid derived fields on attributes users must filter on unless they are backed accordingly. See query
fields. - Express filters so they hit indices—especially date/time comparisons. See criteria matching.
- Enable the type-aware criteria evaluator and avoid criteria that force full linear scans when indexes exist. See Data Server configuration.
- For heavy read paths, review LMDB allocation, compression, serialization (Kryo vs Fory), and
batchingPeriodon the Data Server—especially when latency spikes onDATA_LOGONorMORE_ROWS. - When users edit shared records, enable optimistic concurrency on the server (configuration) and ensure edit events carry the record timestamp. Entity Manager and generated forms surface concurrency failures via submit-failure notifications.
For static or slowly changing lookup tables, consider process cache with indices that match your joins.
5. Manage real-time communication
- Prefer WebSocket when push updates are required: Connect overview,
DefaultConnect(WebSocket), and WebSocket vs HTTP. - Subscribe only to resources the screen needs; tear down streams in component cleanup (see Avoiding browser memory leaks).
- For HTTP mode, use HTTP Connect (
DefaultHttpConnect) and tunePOLLING_INTERVAL_MAPandPOLLING_FREQUENCYso polling does not overwhelm the server. Router defaults are documented under Genesis router. - Metadata is cached client-side; see metadata.
Subscription timeouts and client channel capacity also affect how many concurrent subscriptions a user can hold—see Genesis router.
6. Application structure
Scattering large observable state across many components can degrade UI responsiveness. For non-trivial apps, centralise domain state (for example with Foundation Store) instead of duplicating live data in every component.
7. Measure in development and production
During development
For day-to-day performance work on large grids and subscriptions, browser tooling tends to be more actionable than generic page-speed scores:
- Network requests — Run the client with HTTP Connect (
DefaultHttpConnect) when you need to inspect traffic. Polling and request/response calls show up as normal HTTP requests in the browser Network panel, which makes it easier to see how often resources are polled, how large responses are, and whether screens subscribe to more queries than they need. Tune intervals usingPOLLING_FREQUENCYandPOLLING_INTERVAL_MAP(see Connect configuration). Use WebSocket in production when push is required; switch to HTTP temporarily while diagnosing load. - Memory allocation — Use the browser Memory (or Performance) tools to take heap snapshots and compare allocation before and after opening a grid, scrolling, or changing routes. Spikes often point to client-side datasource caches, metadata, or grid data that is not released when leaving a page. See Avoiding browser memory leaks for a structured DevTools workflow and common UI patterns (FAST and React).
On the server, use Data Server start-up logs and LMDB allocation when investigating memory pressure from large queries.
In production
- Enable metrics to spot Data Server, JVM, and executor pressure early. See Operate — Metrics.
- Use tracing for end-to-end latency on inbound HTTP/WebSocket messages when you need to tie a slow UI update to a specific message type. See Operate — Tracing.
Related how-to
- Consume a REST API — Request Server pagination and infinite scrolling in a grid for external data.
Reading order
- Grids overview
- Data Server or Request Reply on this page
- Data Server — rows and view
- Grid Pro datasources
- Entity Manager if you use CRUD micro front-ends
- Avoiding browser memory leaks for client-side retention and cleanup
- Options datasource for large select and combobox lists
- Caching and compressing HTTP responses for data served from custom endpoints