Case Study: Scaling AI Workflows with React
Notes from building a drag and drop agent pipeline editor with React Flow and Zustand, including the render problems that showed up past a few hundred nodes.
Emily Blunt/2 min read
An enterprise client came to us with a familiar problem: their team wired up LLM pipelines in Python config files, and nobody but the author could tell what any pipeline did. They wanted a canvas. Drag nodes, connect edges, run the chain, watch it execute.
The stack
- Frontend: React, Vite, React Flow
- Orchestration: LangChain on a Python backend
- State: Zustand
Why React Flow
An agent chain is a directed graph, so we needed a graph editor, and writing your own pan and zoom canvas is a monthlong detour we declined to take. React Flow gives you nodes, edges, selection, and viewport handling out of the box, and it only mounts the nodes in view, which starts to matter once graphs get big.
Each model type (GPT-4, Claude 3, Llama 2) got its own custom node with inline parameter controls.
import { memo } from 'react';
import { Handle, Position } from 'reactflow';
const ModelNode = memo(({ data }) => (
<div className="model-card">
<div className="header">{data.modelName}</div>
<label>Temperature: {data.temperature}</label>
<Handle type="source" position={Position.Bottom} />
</div>
));
The one rule with custom nodes: memoize them. React Flow re-renders nodes during viewport changes, and an unmemoized node with a few inputs makes dragging feel like wading through mud.
Live execution state
When a chain runs, the backend streams per node status over a WebSocket. Updates land in a Zustand store keyed by node id, and each node subscribes to its own slice with a selector. That was the entire performance story. Our first version pushed status through React Flow's node data and re-rendered the whole graph on every event. The selector version re-renders one node.
It held up fine with 50 concurrent runs in testing. Past a few hundred visible nodes the edges got expensive to draw, so we swapped bezier paths for straight lines at low zoom levels. Nobody noticed, which was the point.
What we took away
The AI half of this project was the easy half. LangChain did what its docs said it would. The real work was graph state, render discipline, and making a canvas feel solid under a drag. React's ecosystem covered all of it, which is more than we expected going in.
Related reading
Top 5 React Libraries for Building AI InterfacesThe five libraries that end up in almost every AI interface we ship, and the caveats we wish someone had told us about each one.Resources2 min readOptimizing LLM Integrations in ReactModel inference is slow and metered per token. Most of the fix lives in the UI layer: optimistic rendering, debounced requests, and counting tokens before you send them.Optimization2 min readAI Agents Belong Behind React Server ComponentsAgents need API keys, database access, and internal tools. None of that belongs in a browser, which makes the RSC boundary a convenient place to draw the line.Architecture2 min read