There's a specific moment in every graph visualization project when everything falls apart. The demo works beautifully with 100 nodes. The prototype feels snappy with 500. Then you load real data—10,000 entities, 200,000 relationships—and the browser tab freezes. Dragging a node takes a full second to respond. Zooming feels like scrolling through molasses.
That moment is where React Flow stops being the right tool. Not because it's poorly built—it's an excellent library for what it does. But what it does is render every node as a DOM element. At a few hundred nodes, that's fine. At a few thousand, the browser's paint engine starts to choke. At tens of thousands, it's not slow. It's unusable.
This guide is about what comes after React Flow. It covers the WebGL-based graph libraries that handle large-scale networks, the architectural patterns that make them perform, and the decision framework for choosing the right one. If you're still evaluating general-purpose graph libraries, our React graph library guide covers the broader landscape. This post is specifically about the WebGL and large-scale angle.
Why React Flow Breaks at Scale (And Why It's Not React Flow's Fault)
React Flow renders every node as a React component. Every edge is an SVG path. Every interaction triggers React state updates. For a diagram with 50 nodes, this is a delight. For a network with 10,000 nodes, it's a performance disaster.
The numbers are stark. React Flow handles roughly 500 nodes at 60fps before lag becomes noticeable[reference:0]. With aggressive viewport culling and optimization, it might stretch to 2,000–5,000 nodes, but you're fighting the architecture at every step[reference:1]. The library's own performance documentation points to unnecessary re-renders and direct state access as the primary culprits[reference:2].
This isn't a criticism of React Flow. It's a DOM-based library, and the DOM has limits. The browser's layout and paint engines weren't designed to animate 10,000 DOM elements simultaneously. Every node is a real element that participates in layout, receives events, and contributes to the render tree. You can optimize around the edges, but you can't escape the fundamental constraint.
The same applies to any SVG-based graph library. SVG creates a DOM node per element. At 1,000–2,000 nodes, performance degrades. At 10,000, it collapses[reference:3]. Canvas-based libraries push the ceiling higher—roughly 10,000 nodes—because they draw to a single bitmap instead of thousands of DOM nodes. But past 10,000, even Canvas struggles.
WebGL is the next tier. It renders directly on the GPU, bypassing the DOM entirely. The performance ceiling jumps from thousands to tens of thousands—and in some cases, millions—of nodes.
The Rendering Hierarchy: SVG, Canvas, and WebGL
The choice of rendering technology determines your maximum node capacity more than any other factor. Here's the practical hierarchy.
| Rendering | Max nodes (interactive) | How it works | React examples |
|---|---|---|---|
| SVG | 1,000–2,000 | DOM node per element | React Flow, D3 SVG, Cytoscape (DOM mode) |
| Canvas | ~10,000 | Single bitmap, drawn imperatively | react-force-graph-2d, Cytoscape Canvas |
| WebGL | 50,000–1,000,000+ | GPU-parallel rendering | Sigma.js, Cosmograph, reagraph, Three.js |
The jump from SVG to Canvas is roughly an order of magnitude. The jump from Canvas to WebGL is another order of magnitude, sometimes two. If your graph is going to exceed a few thousand nodes, WebGL is the only sustainable choice.
But WebGL comes with a tradeoff: customization is harder. SVG nodes are DOM elements—you can style them with CSS, attach arbitrary event handlers, and use React components inside them. WebGL nodes are pixels on a texture. Styling, interaction, and rendering are all custom code. You gain performance and lose flexibility. The right choice depends on whether your graph's scale justifies that trade.
The WebGL Graph Libraries That Actually Work in React
Several libraries bring WebGL graph rendering to React. Here are the ones that are actively maintained and production-ready in 2026.
Sigma.js + react-sigma: The 2D WebGL Standard
Sigma.js is the most widely used WebGL graph library in the JavaScript ecosystem. It renders 2D graphs using WebGL, pairs with Graphology for graph data structures and layout algorithms, and has an official React wrapper (@react-sigma/core) and a modern community wrapper (nx-react-sigma).
Node capacity: 50,000+ nodes in 2D[reference:4]. With aggressive culling and level-of-detail rendering, it can handle more. The library's own documentation says it handles large graphs "well out of the box" and only starts to require tuning at hundreds of thousands of edges[reference:5].
Why it works: Sigma.js uses WebGL 2.0 for hardware-accelerated rendering, offloads ForceAtlas2 layout to a Web Worker via graphology-layout-forceatlas2, and supports edge programs like EdgeLineProgram (fast, 1px lines) and EdgeRectangleProgram (thicker, more geometry)[reference:6]. The Graphology data layer provides graph algorithms, filtering, and community detection without forcing everything through React state.
The catch: Sigma.js is 2D only. If you need 3D spatial visualization, you'll need a different tool. And while react-sigma makes integration straightforward, the wrapper is less mature than the core library. nx-react-sigma addresses this with use-context-selector to minimize re-renders and maintain 60fps during frequent position updates[reference:7].
When to choose it: Your graph is large, 2D is sufficient, and you want a mature, MIT-licensed library with a strong ecosystem around Graphology.
Cosmograph: The GPU Force Simulation Powerhouse
Cosmograph is the fastest web-based library for large network graph visualization, built on WebGL with a GPU-accelerated force layout engine. It's the library you reach for when Sigma.js isn't enough.
Node capacity: The library's comparison page is explicit: it supports GPU force simulation for more than 50,000 points, while Sigma.js and react-force-graph-3d do not. It can render more than 1 million points and links (Sigma.js can too, but react-force-graph-3d cannot)[reference:8].
The key differentiator is that both simulation and rendering run on the GPU. In CPU-bound 3D libraries, large graphs slow down or freeze because the force simulation is the bottleneck, not the rendering. Cosmograph eliminates that bottleneck by moving the simulation to the GPU as well[reference:9].
Why it works: The @cosmograph/react package provides React components and providers. The core @cosmograph/cosmos engine (formerly cosmos.gl) is a WebGL Force Graph algorithm and rendering engine that can simulate networks of hundreds of thousands of points and links in real time on modern hardware[reference:10].
The catch: Cosmograph is newer and less widely adopted than Sigma.js. The API is different, and the ecosystem is smaller. But for pure performance at scale, it's the strongest option.
When to choose it: You need GPU force simulation for 50,000+ points, or you need to render 1 million+ points and links. It's the performance ceiling for React graph libraries.
reagraph: The React-Native WebGL Option
reagraph is a high-performance network graph visualization built in WebGL for React. It's part of the Reaflow/Reablocks ecosystem and focuses specifically on graph rendering at scale.
Node capacity: 10,000+ nodes with smooth rendering[reference:11]. Not as high as Sigma.js or Cosmograph, but significantly better than any DOM-based option.
Why it works: It uses WebGL for rendering and provides built-in layouts (force-directed, circular, tree, hierarchical, radial). Features like path finding, expand/collapse, lasso selection, and edge bundling are included out of the box[reference:12].
The catch: The node capacity is lower than Sigma.js and Cosmograph. It's a strong React-first option for mid-scale graphs (10k nodes), but it's not the tool for million-node datasets.
When to choose it: You want a React-first WebGL library with built-in layouts and don't need to push past 10,000–20,000 nodes.
@cocorof/graphier: Three.js-Based 3D/2D with Extreme Scale
@cocorof/graphier is a high-performance 3D/2D graph renderer for React, powered by Three.js and d3-force-3d. It's designed for maximum GPU efficiency.
Node capacity: For 2D overview rendering, it's built for 100,000+ nodes and about 1 million edges when the layout is computed once on the server[reference:13]. For interactive 3D, it handles thousands of nodes with 2 GPU draw calls (InstancedMesh for nodes, LineSegments for edges)[reference:14].
Why it works: It uses two GPU draw calls for the entire graph, runs the force layout in a Web Worker, and includes post-processing (UnrealBloomPass), custom GLSL shaders, and automatic level-of-detail scaling. The architecture is built for performance from the ground up[reference:15].
The catch: It's a newer library with a smaller community. The 3D interactive mode is limited to thousands of nodes; the 100k+ capacity is for 2D overview rendering with precomputed layouts.
When to choose it: You need 3D visualization with Three.js and want extreme GPU efficiency, or you need a 2D overview renderer for 100k+ nodes.
react-force-graph-3d: Three.js/WebGL for Smaller 3D Graphs
react-force-graph-3d is part of the react-force-graph family. It uses Three.js and WebGL for 3D rendering and d3-force-3d for physics.
Node capacity: The 3D WebGL component handles roughly 10,000–20,000 nodes before performance degrades[reference:16]. It's not in the same class as Sigma.js or Cosmograph for raw scale.
Why it works: It's declarative, supports 2D/3D/VR/AR, and has a large community. The ngraph physics engine is available as a high-performance alternative for large graphs in 3D[reference:17].
The catch: It's not built for extreme scale. The 2D Canvas component handles more nodes than the 3D WebGL component, which is counterintuitive but reflects the overhead of 3D rendering.
When to choose it: You need 3D visualization for a graph in the 5,000–15,000 node range and want a declarative React API.
The Honorable Mentions
@nexgraph/core is a GPU-first, framework-agnostic WebGL2 toolkit for 3D graph visualization at scale (large node counts, millions of edges, LOD, workers)[reference:18]. It's a newer entrant with ambitious performance goals.
graspologic-js (Microsoft) is a WebGL-based graph renderer that can handle hundreds of thousands or millions of nodes, using SharedArrayBuffer for efficient memory sharing between the UI thread and Web Workers[reference:19].
Ogma (Linkurious) is a commercial WebGL graph visualization library used for fraud detection and cybersecurity. It handles millions of nodes and edges, and version 5.3 added 10x faster cluster layouts and expanded React support[reference:20][reference:21]. It's the enterprise option when open-source libraries don't meet compliance or support requirements.
The Real Bottleneck: Layout, Not Rendering
Here's the counterintuitive truth about large-scale graph visualization: the rendering is rarely the bottleneck. The layout is.
Force-directed layouts are O(N²) in their naive form. Every node repels every other node, and every edge pulls its endpoints together. At 10,000 nodes, that's 100 million pairwise interactions per simulation tick. No amount of GPU rendering can save you if the layout calculation takes 500ms per frame[reference:22].
The solution is twofold: use an approximation algorithm (Barnes-Hut reduces O(N²) to O(N log N)) and run the simulation in a Web Worker so it doesn't block the main thread. graphology-layout-forceatlas2 ships a worker version out of the box, and Cosmograph moves the entire simulation to the GPU[reference:23].
For truly massive graphs, the pragmatic approach is to compute the layout once on the server and render it with a 2D WebGL view. @cocorof/graphier's OverviewGraph is built exactly for this: 100k+ nodes and 1M edges, with the layout precomputed[reference:24]. Interactive layout is expensive; static layout is cheap.
Architecture Patterns for Large-Scale Graphs in React
The libraries matter, but the architecture matters more. These are the patterns that separate a graph that performs from one that doesn't.
Pattern 1: Don't Put Graph Data in React State
This is the most important rule. Putting 10,000 nodes in useState means every force-simulation tick triggers React reconciliation. The simulation runs at 60fps; React was not designed to reconcile 10,000 objects at 60fps[reference:25].
The fix: Hold the graph in a ref or in Graphology's store. Let React own the chrome—toolbars, panels, search, filters—and let the graph own itself. Pass the graph instance to the renderer, not the data.
// Bad: graph data in React state
const [nodes, setNodes] = useState(initialNodes);
// Good: graph instance in a ref
const graphRef = useRef(new Graph());
useEffect(() => {
graphRef.current.import(initialData);
}, []);
Pattern 2: Diff, Don't Replace
Passing a new array prop to the graph component triggers a full attribute recalculation. For large graphs, that's expensive. Instead, mutate the Graphology instance and call sigma.refresh(). Only the changed attributes are recalculated[reference:26].
// Bad: full replacement
<Sigma graph={{ nodes: newNodes, edges: newEdges }} />;
// Good: mutation + refresh
graphRef.current.mergeNode("new-node", { x: 10, y: 20 });
sigmaRef.current.refresh();
Pattern 3: Match the Renderer to the Scale
SVG dies around 1,000–2,000 nodes. Canvas gets you to roughly 10,000. Past that, WebGL. Don't try to force an SVG renderer past its limits—you'll spend weeks optimizing and still lose[reference:27].
Pattern 4: Cull and Level-of-Detail
Zoomed out, users can't read 50,000 labels anyway. Render nodes as gl.POINTS, hide labels, hide edges entirely. A density heatmap at zoomed-out levels communicates more than a hairball of edges[reference:28].
Sigma.js and Cosmograph both support level-of-detail rendering. Use it. The performance gain is dramatic, and the visual result is often clearer.
Pattern 5: Edges Are the Silent Killer
10,000 nodes with an average degree of 20 means 200,000 edges per frame. Edges dominate the GPU workload, not nodes. Sigma's EdgeLineProgram (gl.LINES) is the fastest option but only supports 1px lines. EdgeRectangleProgram gives you thickness but doubles the geometry. Edge transparency at scale tanks performance—use very thin edges to fake it[reference:29].
Performance Benchmarks: What the Numbers Actually Say
The published benchmarks confirm the hierarchy. WebGraphViz, a WebGL-based retail analytics tool built with Sigma.js and Graphology, maintained over 100 FPS up to 5,000 nodes in a best-case environment, while its SVG counterpart dropped to near 0 FPS as dataset size increased[reference:30]. In a worst-case environment (60 FPS cap), WebGL stayed around 30 FPS at scale while SVG collapsed[reference:31].
Cosmograph's comparison page reports that it supports GPU force simulation for more than 50,000 points, while Sigma.js and react-force-graph-3d do not. It also renders more than 1 million points and links, matching Sigma.js and exceeding react-force-graph-3d[reference:32].
React Flow, for reference, handles roughly 500 nodes at 60fps before lag becomes noticeable. A canvas-based React Flow-compatible library claims 5,000+ nodes at 60fps, which illustrates the gap between DOM and Canvas rendering[reference:33].
The practical takeaway: if you're under 2,000 nodes, React Flow is fine. Between 2,000 and 10,000, Canvas-based libraries like react-force-graph-2d are adequate. Past 10,000, WebGL is the only sustainable choice. Past 50,000, you need GPU force simulation (Cosmograph) or precomputed layouts.
A Decision Framework
Here's the decision tree I use when recommending a large-scale graph library.
1. How many nodes and edges?
- Under 2,000: React Flow or Cytoscape.js.
- 2,000–10,000: react-force-graph-2d (Canvas) or reagraph (WebGL).
- 10,000–50,000: Sigma.js + react-sigma (2D) or react-force-graph-3d (3D, if under ~15k).
- 50,000+: Cosmograph (GPU force simulation) or @cocorof/graphier (precomputed layout, 2D overview).
2. Do you need 2D or 3D?
- 2D: Sigma.js is the standard. Cosmograph also supports 2D.
- 3D: react-force-graph-3d (up to ~15k), @cocorof/graphier (Three.js), or Cosmograph 3D (GPU simulation).
3. Do you need interactive force simulation at scale?
- Yes: Cosmograph (GPU simulation) or Sigma.js with ForceAtlas2 worker.
- No (precomputed layout is acceptable): @cocorof/graphier's OverviewGraph or a custom WebGL renderer.
4. What's your licensing constraint?
- Open-source (MIT/Apache): Sigma.js, Cosmograph, reagraph, react-force-graph, @cocorof/graphier.
- Commercial: Ogma (enterprise support, millions of nodes).
For most teams building a large-scale 2D network graph in React, the starting point is Sigma.js with react-sigma and Graphology. It's mature, MIT-licensed, handles 50,000+ nodes, and has a strong ecosystem. If you need GPU force simulation beyond that, Cosmograph is the next step. If you need 3D, @cocorof/graphier or react-force-graph-3d depending on your scale.
A Real Story: Migrating from React Flow to Sigma.js
A client came to me with a knowledge graph visualization built on React Flow. The graph had about 8,000 nodes and 40,000 edges—a medium-sized dataset by knowledge graph standards. The dashboard was supposed to let analysts explore relationships, but it was unusable. Dragging a node took a full second to respond. Zooming out caused a multi-second freeze. The analysts had given up on it and were exporting data to spreadsheets instead.
We migrated to Sigma.js with Graphology and react-sigma. The migration took about two weeks. The biggest change wasn't the rendering library—it was the architecture. We moved the graph data out of React state and into a Graphology instance stored in a ref. We moved the ForceAtlas2 layout into a Web Worker. We switched to EdgeLineProgram for the edges, accepting 1px lines in exchange for the performance.
The result was a graph that rendered 8,000 nodes and 40,000 edges at 60fps. Dragging a node responded instantly. Zooming was smooth. The analysts started using it again. The lesson wasn't that React Flow is bad—it was that the rendering architecture was mismatched to the data scale. React Flow is excellent for diagrams; Sigma.js is built for networks at scale.
Common Pitfalls to Avoid
Putting graph data in React state. Covered above, but it's worth repeating. This is the most common performance mistake in React graph visualization. The simulation ticks, React reconciles, the browser stutters. Store the graph in a ref.
Using SVG for a network graph. SVG creates a DOM node per element. At 2,000 nodes, you're already in trouble. Use Canvas or WebGL.
Ignoring the layout cost. Rendering is fast; layout is slow. Run ForceAtlas2 in a Web Worker, use Barnes-Hut approximation, or precompute the layout on the server.
Not culling edges at low zoom. Edge rendering is the dominant GPU cost. At zoomed-out levels, hide edges entirely or render them as a density heatmap.
Assuming WebGL is automatically faster. WebGL has overhead—shader compilation, buffer management, context switching. For 100 nodes, SVG is faster and easier. WebGL only wins at scale.
Forgetting to dispose of WebGL contexts. WebGL contexts are a limited resource. If you unmount and remount a graph component without disposing of the context, you'll exhaust the browser's limit and the graph will stop rendering. Clean up on unmount.
If you've been working through our React charting library for large datasets guide, many of the same performance principles apply: canvas over SVG, downsampling, memoization, and avoiding unnecessary re-renders.
Wrapping Up
WebGL network graph visualization in React is a different discipline from building a flowchart with React Flow. The libraries are different, the architecture is different, and the performance ceiling is orders of magnitude higher.
The hierarchy is clear: SVG for hundreds of nodes, Canvas for thousands, WebGL for tens of thousands to millions. Sigma.js is the mature 2D WebGL standard with Graphology. Cosmograph is the GPU force simulation leader for 50,000+ points. reagraph is the React-first mid-scale option. @cocorof/graphier is the Three.js 3D option with extreme 2D overview capacity.
But the library is only half the story. The architecture—graph data in refs, layout in workers, edges culled at zoom, level-of-detail rendering—is what makes a large-scale graph perform. Get the architecture right, and any of the WebGL libraries will serve you well.
For the broader graph library landscape, see our React graph library guide. For the full visualization ecosystem, see our React data visualization libraries. And for large-scale performance patterns across all visualization types, see our React charting library for large datasets guide.
Now go render a graph that doesn't freeze.
Need help building a large-scale network graph visualization in React? Red Surge Technology specializes in high-performance data visualization for complex domains. Get in touch to discuss your project.