Lumeo

Performance Facts

Real numbers from one local machine, measured against real interactions — DataGrid rendering a large dataset, the resize/reorder hot paths, a toast burst, and WASM boot time. Same honesty standard as Bundle Facts: the exact methodology per metric, an honest reproduce section, and the caveats we hit along the way.

Performance

Column reorder moves cost 0.0000 ms of JS per move event

Median of 3,000 synthetic pointer moves against a loaded grid, measured 2026-07-12 (4.2.0+main) on one local Windows machine — see "How each metric was measured" below. (Resize's own number is enqueue-only handler cost, not directly comparable — see below.)

The measured numbers

Median of 5 independent runs per metric, fresh browser page per run. Full per-run data lives in scripts/perf/results/*.json.

5.2 s

DataGrid initial render

10,000 rows, click-to-first-row, virtualized

55 fps

Virtualized scroll

10,000 rows, 1s scroll sweep

261 ms

Sort 10k rows

Click header → aria-sort flips + re-render

341 ms

Filter 10k rows

Toolbar search input → body re-renders

0.0033 ms

Column resize (enqueue-only)

Handler cost per move; excludes the deferred rAF width write

0.0112 ms

Column reorder

Per pointer-move event, live sibling-shift

532 ms

Toast burst settle

5 toasts (see MaxToasts crash caveat)

817 ms

WASM boot-to-interactive

Trigger → MainLayout first interactive render

How each metric was measured

All four scripts drive docs/Lumeo.Docs/Pages/E2E/PerfBench.razor (a noindex, nav-less harness page — same pattern as the existing P0Harness.razor) or the docs home, with Playwright.

Caveats

This is not a lab. Read these before quoting a number.

Single local Windows dev machine, not a CI runner or a lab bench. Absolute numbers will differ on your hardware — the relative shape (hot paths sub-millisecond, bulk operations low-hundreds-of-ms) is the more portable takeaway.

Chromium only, via Playwright headless. No Firefox/WebKit/mobile numbers here.

Served by dotnet run's Development dev-server, not a published, CDN-hosted production build — real production latency will differ (mostly for network-bound metrics; the in-page timings above don't depend on transport).

This build is non-AOT-compiled (interpreter tier). AOT-published apps trade a slower build for a materially faster runtime — the DataGrid bulk-operation numbers above are pessimistic relative to what an AOT-published app would show.

DataGrid's automated dataset is 10,000 rows, not the 100,000 this page's title once implied — see "Why 10k rows, not 100k" above for the measured 100k OOM and the 75k/~60s render finding.

The toast burst is 5 toasts, not 100 — see "A real bug, disclosed rather than hidden" above.

The column-resize figure (0.0033 ms) is enqueue-only handler cost and excludes the deferred rAF DOM write a real drag pays — it is not directly comparable to reorder's figure, which includes its (synchronous) DOM write. See "Column resize / reorder" above.

The WASM boot number is measured against the docs app's DEFAULT (auto-calculated ~108 MB) heap, not the 512 MB perf heap the DataGrid/toast benchmarks below use — see "How to reproduce" for why boot needs a separate server session.

How to reproduce

Every script and its full per-run JSON output lives in the repo — scripts/perf/. We believe the numbers; check them yourself.

# 1a. Boot cost — DEFAULT heap (what real visitors get)
export DOTNET_ROLL_FORWARD=Major
cd docs/Lumeo.Docs
dotnet run --arch x64 -c Release --urls http://localhost:5287

# in another shell
cd scripts/perf
npm install
node wasm-boot.mjs
# stop the server, then:

# 1b. DataGrid / hot-path / toast benchmarks — need the 512 MB perf heap
cd docs/Lumeo.Docs
dotnet run --arch x64 -c Release --urls http://localhost:5287 -p:LumeoPerfHeap=true

# in another shell
cd scripts/perf
node datagrid-100k.mjs
node datagrid-hotpaths.mjs
node toast-burst.mjs

Two server sessions on purpose — WasmInitialHeapSize is a publish-time property for the whole app, not scoped per route, so an accurate boot number needs a session without the perf heap. See scripts/perf/README.md.

See it for yourself

Run the scripts, read the JSON, poke at the harness page. We'd rather you distrust a number and check it than take our word for it.