We rebuilt the Kibana APM service map in Elastic Observability on React Flow. At 500 services it renders in 64ms, roughly 6x faster than the previous Cytoscape.js implementation, and ships 60% less JavaScript (69 KiB vs 172 KiB). Service nodes now show alert, SLO, and anomaly health so you can filter to breaching services only and embed the result on any Kibana dashboard, with full keyboard navigation across the topology. From alert to failing dependency in four clicks: Elastic APM's embedded service map covers the alert panel, SLO badges, and dashboard embedding in more depth.
Here's the map before this rebuild, and after:
| Before | After |
|---|---|
Why the APM service map moved from Cytoscape.js to React Flow graph visualization
The payoff is concrete: React Flow renders nodes as real React components instead of a canvas draw loop, so panning and zooming stay smooth on large topologies, our Elastic UI (EUI) nodes and badges render natively (no more re-rendering the full canvas on every update), and DOM-based rendering makes nodes naturally visible to screen readers, unlike canvas-based rendering.
It's lighter, too: the graph library dropped from 172.4 KiB (cytoscape.js) to 69 KiB (@xyflow/react), about 103 KiB less JavaScript to ship, #248470.
How much faster is the APM service map with React Flow?
Before committing to the APM service map migration from Cytoscape.js to React Flow, we benchmarked both libraries at 100, 200, and 500 services (a synthetic chain topology, measured via Lighthouse and component-level timings averaged over multiple runs, #248470):
| 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 draws the map in ~64 ms versus Cytoscape.js's ~393 ms, roughly 6x faster. The underlying graph layout step alone got ~70-78% faster. Total main-thread blocking time dropped ~20%, and peak memory was slightly lower despite rendering everything as real DOM. Those results and more are available in the benchmark results comment.
Keyboard navigation and accessibility in the APM service map
The map now announces your position in the topology as you navigate, with live screen-reader context for every interaction (#251444).
-
Spatial arrow-key navigation: arrow keys navigate based on visual proximity rather than logical document order. Focus moves to the nearest service in the visual direction you press, even through complex serpentine folds.
-
Direct shortcuts: launch flyouts with Enter or Space, and dismiss them with Escape.
-
Live announcements: every interaction is backed by a screen-reader announcement, such as "Selected connection from A to B."
How the APM service map layout algorithm works
The APM service map uses Dagre for hierarchical graph layout, then applies serpentine folding to prevent long dependency chains from producing unreadable high-aspect-ratio strips:
-
Dagre hierarchical layout: we use Dagre, a graph layout engine, with a direction toggle between horizontal and vertical that you can change from the options panel. If Dagre fails to compute a layout, the map falls back to a deterministic grid so it stays interactive and error-free.
-
Serpentine folding for long chains: long dependency pipelines produce thin, unreadable strips that require heavy zooming. When the aspect ratio becomes too extreme, we wrap ranks into stacked bands that snake back and forth, so "fit view" can zoom in much tighter on the actual services. If the topology is already compact or has too many cross-band edges, we skip folding. (#272900).
Service dependency mapping and Kibana dashboard embedding under the hood
The visual refresh is the easy part to see. Some of the architecture changes that underpin the rebuilt map are:
Unified resource nodes for cleaner service dependency mapping
We now group external dependencies into unified resource nodes, reducing visual noise. We also fixed message-queue span grouping so those patterns no longer create orphaned nodes (#252713).
Service map flyout charts powered by ES|QL and Lens
The service flyout's infrastructure and RED metrics use ES|QL and Kibana's core Lens visualization engine, giving the map the same charting experience used across Kibana (#273713).
Embedding the service map on any Kibana dashboard
Adding a service map to a dashboard takes one click.
Open the "Copy to dashboard" menu from any map view in APM, and the panel carries your current environment, service filter, KQL query, and filter chips directly across.
Relative time ranges like now-15m transfer as-is rather than freezing to an absolute timestamp, so the panel stays live on the dashboard (#272277).
Once embedded, the panel adapts to where it lives. It shows or hides controls based on view mode, and respects global time settings without overwriting your relative ranges (#274551).
What's next for the APM service map
The service map rebuild is a foundation, not a finish line. Beyond what's available in 9.5, some of what's coming next is already on the APM service map roadmap.
Contributors
I led this migration and built these features alongside a great team. Thanks to Samuel Brito, Gonçalo Rica Pais da Silva, Irene Blanco Fabregat, Carlos Crespo, Miriam Aparicio Garcia, Sandra G, and Nathan Smith for the engineering, and to Karolina Kurstak and Roshan Gonsalkorale for the design and product work.