6x Faster at 500 Services: How Elastic Rebuilt the Kibana APM Service Map from Canvas to React DOM
Key takeaways
- Elastic's React Flow rebuild renders the Kibana APM service map about 6x faster at 500 services — 64.1 ms versus 392.5 ms with the previous Cytoscape.js canvas implementation.
- The graph library bundle shrank from 172.4 KiB to 69 KiB (~103 KiB less JavaScript), main-thread blocking time dropped around 20%, and peak memory stayed slightly lower despite DOM-based rendering.
- The rebuilt map is fully keyboard-navigable and screen-reader accessible: spatial arrow-key navigation, Enter/Space to open flyouts, and live announcements for every interaction.
- Layout combines the Dagre hierarchical engine with serpentine folding, which wraps long dependency chains into stacked bands instead of unreadable thin strips.
- Service maps now embed on any Kibana dashboard with one click, carrying environment filters, KQL queries, and relative time ranges like "now-15m" across live rather than frozen to absolute timestamps.
Elastic rebuilt the service map in Kibana APM, replacing the canvas-based Cytoscape.js implementation with React Flow (@xyflow/react). Jenny Pavlova of Elastic documented the migration on Elastic Observability Labs, covering the benchmark results behind the decision, the new layout algorithm, the accessibility work, and the dashboard-embedding behavior that ships with the rebuilt map in version 9.5.
Why did Elastic move the Kibana APM service map from Cytoscape.js to React Flow?
Elastic’s engineers moved the Kibana APM service map to React Flow because it renders nodes as actual React components instead of relying on canvas draw loops, which keeps panning and zooming smooth across large topologies. Elastic UI (EUI) nodes and badges now render natively without requiring full canvas re-renders on each update. DOM-based rendering also provides inherent accessibility advantages: nodes are naturally visible to screen readers, unlike canvas implementations.
The library footprint shrank considerably with the change. The graph library decreased from 172.4 KiB (Cytoscape.js) to 69 KiB (@xyflow/react) — approximately 103 KiB less JavaScript shipped overall.
How much faster is the APM service map with React Flow?
Before committing to the migration, the Elastic team benchmarked both libraries at 100, 200, and 500 services using a synthetic chain topology, measured via Lighthouse and component-level timings across multiple runs:
| Services | Cytoscape.js render | React Flow render | Faster by |
|---|---|---|---|
| 100 | 61.6 ms | 15.0 ms | ~76% |
| 200 | 102.5 ms | 28.1 ms | ~73% |
| 500 | 392.5 ms | 64.1 ms | ~84% |
At 500 services, React Flow renders the map in approximately 64 milliseconds versus roughly 393 milliseconds for Cytoscape.js — a sixfold performance improvement. The underlying graph layout step alone became 70–78% faster. Total main-thread blocking time decreased around 20%, and peak memory usage remained slightly lower despite rendering everything as real DOM elements.
How does keyboard navigation and accessibility work in the rebuilt service map?
The rebuilt Kibana APM service map announces the user’s position within the topology during navigation, with live screen-reader context supporting every interaction.
Spatial arrow-key navigation lets users navigate based on visual proximity rather than logical document order: focus moves to the nearest service in the visual direction pressed, even navigating through complex serpentine folds. Direct shortcuts launch flyouts with Enter or Space, and Escape dismisses them. Live announcements back every interaction with screen-reader output — for example, “Selected connection from A to B.”
How does the APM service map layout algorithm work?
The Kibana APM service map uses Dagre for hierarchical graph layout, then applies serpentine folding to prevent long dependency chains from creating unreadable high-aspect-ratio strips.
Dagre hierarchical layout: the Dagre graph layout engine drives node positioning, with a direction toggle between horizontal and vertical adjustable from the options panel. If Dagre fails to compute a layout, the map falls back to deterministic grid rendering, keeping it interactive and error-free.
Serpentine folding for long chains: long dependency pipelines otherwise produce thin, unreadable strips that require excessive zooming. When the aspect ratio becomes too extreme, Elastic’s algorithm wraps ranks into stacked bands that snake back and forth, allowing “fit view” to zoom significantly tighter on actual services. If the topology is already compact or contains too many cross-band edges, folding is skipped.
What changed in service dependency mapping and dashboard embedding?
How do unified resource nodes reduce visual clutter?
External dependencies in the Kibana service map now group into unified resource nodes, reducing visual noise. The Elastic team also fixed message-queue span grouping patterns that previously created orphaned nodes.
What powers the service map flyout charts?
The service flyout’s infrastructure and RED metrics leverage ES|QL and Kibana’s core Lens visualization engine, delivering the same charting experience found across Kibana. Service nodes surface alert, SLO, and anomaly health indicators, and users can filter the map to breaching services.
How does embedding the service map on a Kibana dashboard work?
Adding a service map to a dashboard takes a single click: users open the “Copy to dashboard” menu from any map view in APM, and the panel carries the current environment, service filter, KQL query, and filter chips directly across. Relative time ranges like “now-15m” transfer as-is rather than freezing to absolute timestamps, keeping the panel live on dashboards.
Once embedded, the panel adapts to its location: controls display or hide based on view mode, and global time settings are respected without overwriting relative ranges.
What’s next for the APM service map?
Elastic describes the service map rebuild as a foundation rather than a final product. Beyond the features available in version 9.5, the Elastic team has outlined additional developments on the APM service map roadmap.
Frequently asked questions
How much faster is the Kibana APM service map after the React Flow migration?
At 500 services, the React Flow implementation renders in 64.1 ms versus 392.5 ms with the previous Cytoscape.js implementation — roughly a sixfold improvement. At 100 services rendering improved from 61.6 ms to 15.0 ms (~76% faster), and at 200 services from 102.5 ms to 28.1 ms (~73% faster).
How much JavaScript did the migration eliminate from Kibana?
The graph library bundle shrank from 172.4 KiB (Cytoscape.js) to 69 KiB (@xyflow/react) — approximately 103 KiB less JavaScript shipped overall.
What accessibility features did the rebuilt service map add?
Spatial arrow-key navigation that moves focus to the nearest service in the visual direction pressed, direct shortcuts (Enter or Space to open flyouts, Escape to dismiss), and live screen-reader announcements for every interaction, such as "Selected connection from A to B."
How does the service map layout handle long dependency chains?
Elastic uses the Dagre engine for hierarchical layout, then applies serpentine folding: when the aspect ratio becomes too extreme, ranks wrap into stacked bands that snake back and forth, so "fit view" can zoom in much tighter. If the topology is already compact or has too many cross-band edges, folding is skipped.