Skip to main content

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

SituationPrefer
Modest row counts that fit comfortably in memoryClient-side datasource on Grid Pro or default Entity Manager
Large or unbounded tables, heavy sort/filterServer-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 windowData Server with tuned MAX_ROWS / MAX_VIEW / MOVING_VIEW
Infrequent updates or seconds-scale refresh via HTTP pollingRequest Server with criteria-only mode where appropriate
CRUD screens from metadataEntity Manager with tuned datasourceConfig
Read-only or custom grid UXGrid 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 endpointCache and compress the responseETag/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 ServerPrefer Request Reply
Rows change often and you benefit from streaming delta updates over WebSocketRows 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 UXYou 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_ROWS and MAX_VIEW when columns are wide or values are large.
  • For “latest activity” views, prefer a moving live window (MOVING_VIEW = true) over raising MAX_VIEW to 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:

  1. Expose a Data Server query (or Request Reply with criteria-only where indices do not fit).
  2. Define indices on fields users sort and filter on.
  3. Use a server-side grid datasource so CRITERIA_MATCH and ORDER_BY run on the server.
  4. 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.
  5. Cap subscription size with MAX_ROWS / MAX_VIEW; align Entity Manager datasourceConfig.maxRows with 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 — with criteriaOnlyRequest, criteria and sorting are evaluated on the database where supported, so sortable columns are not restricted to Data Server-style indices (see sortableFields in 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.
  • grid-pro-genesis-datasource — on Data Server resources, enable request-visible-columns-only when the grid defines many columns but users typically show a subset. The datasource sends only the FIELDS for 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 static fields where you need a fixed subset.
Platform version

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:

  • criteria and orderBy to limit and order on the server
  • maxRows to cap each fetch
  • fields to omit unused columns (only applies to dataserver)
  • pollingInterval / pollTriggerEvents only 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):

  1. Enable infinite-scroll on options-datasource so only page-size options (default 20) load initially; further pages load when the user scrolls the listbox.
  2. Set a stable order-by when the resource is Request Server–backed, so offset paging stays consistent while the user scrolls.
  3. For comboboxes, expect server-side search: infinite scroll turns on async filtering so typed input sends CRITERIA_MATCH instead of filtering a single page in the browser.
  4. Keep max-view realistic on Data Server–backed dropdowns; paging uses MORE_ROWS on the live subscription and cannot exceed the tracked view.
Platform version

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.

ParameterRole
MAX_ROWSRows per initial load and per MORE_ROWS request
MAX_VIEWMaximum rows tracked for the subscription; 0 allows unbounded growth for infinite scroll without pre-allocating a huge server structure
MOVING_VIEWWhen true, new real-time rows can replace oldest rows once MAX_VIEW is reached
VIEW_NUMBERNon-zero enables pagination mode (page replaces previous rows)

Typical patterns:

  • Fixed live windowMAX_ROWS = MAX_VIEW, MOVING_VIEW = false so updates apply only to visible rows.
  • Infinite scroll — server-side datasource with pagination disabled; consider MAX_VIEW = 0 for scroll growth; use grid row count in server-side infinite scroll.
  • PaginationMAX_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, set request-visible-columns-only so 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 batchingPeriod on the Data Server—especially when latency spikes on DATA_LOGON or MORE_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

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 using POLLING_FREQUENCY and POLLING_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.
  • Consume a REST API — Request Server pagination and infinite scrolling in a grid for external data.

Reading order

  1. Grids overview
  2. Data Server or Request Reply on this page
  3. Data Server — rows and view
  4. Grid Pro datasources
  5. Entity Manager if you use CRUD micro front-ends
  6. Avoiding browser memory leaks for client-side retention and cleanup
  7. Options datasource for large select and combobox lists
  8. Caching and compressing HTTP responses for data served from custom endpoints