React Flow Architecture

existential-birds/beagle/plugins/beagle-react/skills/react-flow-architecture

by existential-birdsd1a74899fbfec74974d1818e4cac7c3d54d44b65No license83 starsListed Oct 9, 2026Updated Oct 9, 2026Repository updated 3 weeks ago

Architectural guidance for building node-based UIs with React Flow. Use when designing flow-based applications, making decisions about state management, integration patterns, or evaluating whether React Flow fits a use case.

Instructions onlySoftware Development
AI-generated overview

Architectural guidance for designing node-based UIs with React Flow, covering fit, state, integration and performance.

What it does
This skill provides architectural guidance for building node-based user interfaces with React Flow. It helps decide whether React Flow fits a use case, choose state management approaches, structure data flow, and handle viewport persistence, backend integration, layout algorithms and performance scaling. It produces design decisions and recommendations rather than code artifacts.
When to use it
Use it when designing flow-based applications or evaluating whether React Flow suits a use case. It is meant for decisions about state management, integration patterns and scaling before implementation.
Requirements
No scripts or tools are required; it is instructions only. It assumes familiarity with React Flow, React and related libraries such as Zustand or dagre when applying the patterns.

React Flow Architecture

When to Use React Flow

Good Fit

  • Visual programming interfaces
  • Workflow builders and automation tools
  • Diagram editors (flowcharts, org charts)
  • Data pipeline visualization
  • Mind mapping tools
  • Node-based audio/video editors
  • Decision tree builders
  • State machine designers

Consider Alternatives

  • Simple static diagrams (use SVG or canvas directly)
  • Heavy real-time collaboration (may need custom sync layer)
  • 3D visualizations (use Three.js, react-three-fiber)
  • Graph analysis with 10k+ nodes (use WebGL-based solutions like Sigma.js)

Decision workflow (gates)

Run this sequence before locking the stack or sprinting implementation. Skip only for throwaway prototypes.

  1. Name the interactions — List the top user actions (e.g. drag, connect, delete, group). Pass: Each action maps to a concrete React Flow callback you will implement (onNodesChange, onConnect, …).

  2. Classify scale — Estimate peak nodes (visible canvas or document total). Pass: Your range matches a row in Node Count Guidelines and you accept the listed strategy (e.g. onlyRenderVisibleElements when that row implies it).

  3. Place state — Choose local hooks, an external store, or Redux/other. Pass: One sentence states where persistence, undo, or cross-surface sync will live, or explicitly “not needed yet.”

  4. Re-check alternatives — If the use case matches Consider Alternatives, Pass: One sentence explains why React Flow still fits or which listed alternative you chose instead.

Architecture Patterns

Package Structure (xyflow)

@xyflow/system (vanilla TypeScript)├── Core algorithms (edge paths, bounds, viewport)├── xypanzoom (d3-based pan/zoom)├── xydrag, xyhandle, xyminimap, xyresizer└── Shared types
@xyflow/react (depends on @xyflow/system)├── React components and hooks├── Zustand store for state management└── Framework-specific integrations
@xyflow/svelte (depends on @xyflow/system)└── Svelte components and stores

Implication: Core logic is framework-agnostic. When contributing or debugging, check if issue is in @xyflow/system or framework-specific package.

State Management Approaches

1. Local State (Simple Apps)
tsx
// useNodesState/useEdgesState for prototypingconst [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);

Pros: Simple, minimal boilerplate Cons: State isolated to component tree

2. External Store (Production)
tsx
// Zustand store exampleimport { create } from 'zustand';
interface FlowStore {  nodes: Node[];  edges: Edge[];  setNodes: (nodes: Node[]) => void;  onNodesChange: OnNodesChange;}
const useFlowStore = create<FlowStore>((set, get) => ({  nodes: initialNodes,  edges: initialEdges,  setNodes: (nodes) => set({ nodes }),  onNodesChange: (changes) => {    set({ nodes: applyNodeChanges(changes, get().nodes) });  },}));
// In componentfunction Flow() {  const { nodes, edges, onNodesChange } = useFlowStore();  return <ReactFlow nodes={nodes} onNodesChange={onNodesChange} />;}

Pros: State accessible anywhere, easier persistence/sync Cons: More setup, need careful selector optimization

3. Redux/Other State Libraries
tsx
// Connect via selectorsconst nodes = useSelector(selectNodes);const dispatch = useDispatch();
const onNodesChange = useCallback((changes: NodeChange[]) => {  dispatch(nodesChanged(changes));}, [dispatch]);

Data Flow Architecture

User Input → Change Event → Reducer/Handler → State Update → Re-render     ↓[Drag node] → onNodesChange → applyNodeChanges → setNodes → ReactFlow     ↓[Connect]   → onConnect → addEdge → setEdges → ReactFlow     ↓[Delete]    → onNodesDelete → deleteElements → setNodes/setEdges → ReactFlow

Sub-Flow Pattern (Nested Nodes)

tsx
// Parent node containing child nodesconst nodes = [  {    id: 'group-1',    type: 'group',    position: { x: 0, y: 0 },    style: { width: 300, height: 200 },  },  {    id: 'child-1',    parentId: 'group-1',  // Key: parent reference    extent: 'parent',      // Key: constrain to parent    position: { x: 10, y: 30 },  // Relative to parent    data: { label: 'Child' },  },];

Considerations:

  • Use extent: 'parent' to constrain dragging
  • Use expandParent: true to auto-expand parent
  • Parent z-index affects child rendering order

Viewport Persistence

tsx
// Save viewport stateconst { toObject, setViewport } = useReactFlow();
const handleSave = () => {  const flow = toObject();  // flow.nodes, flow.edges, flow.viewport  localStorage.setItem('flow', JSON.stringify(flow));};
const handleRestore = () => {  const flow = JSON.parse(localStorage.getItem('flow'));  setNodes(flow.nodes);  setEdges(flow.edges);  setViewport(flow.viewport);};

Integration Patterns

With Backend/API

tsx
// Load from APIuseEffect(() => {  fetch('/api/flow')    .then(r => r.json())    .then(({ nodes, edges }) => {      setNodes(nodes);      setEdges(edges);    });}, []);
// Debounced auto-saveconst debouncedSave = useMemo(  () => debounce((nodes, edges) => {    fetch('/api/flow', {      method: 'POST',      body: JSON.stringify({ nodes, edges }),    });  }, 1000),  []);
useEffect(() => {  debouncedSave(nodes, edges);}, [nodes, edges]);

With Layout Algorithms

tsx
import dagre from 'dagre';
function getLayoutedElements(nodes: Node[], edges: Edge[]) {  const g = new dagre.graphlib.Graph();  g.setGraph({ rankdir: 'TB' });  g.setDefaultEdgeLabel(() => ({}));
  nodes.forEach((node) => {    g.setNode(node.id, { width: 150, height: 50 });  });
  edges.forEach((edge) => {    g.setEdge(edge.source, edge.target);  });
  dagre.layout(g);
  return {    nodes: nodes.map((node) => {      const pos = g.node(node.id);      return { ...node, position: { x: pos.x, y: pos.y } };    }),    edges,  };}

Performance Scaling

Node Count Guidelines

NodesStrategy
< 100Default settings
100-500Enable onlyRenderVisibleElements
500-1000Simplify custom nodes, reduce DOM elements
> 1000Consider virtualization, WebGL alternatives

Optimization Techniques

tsx
<ReactFlow  // Only render nodes/edges in viewport  onlyRenderVisibleElements={true}
  // Reduce node border radius (improves intersect calculations)  nodeExtent={[[-1000, -1000], [1000, 1000]]}
  // Disable features not needed  elementsSelectable={false}  panOnDrag={false}  zoomOnScroll={false}/>

Trade-offs

Controlled vs Uncontrolled

ControlledUncontrolled
More boilerplateLess code
Full state controlInternal state
Easy persistenceNeed toObject()
Better for complex appsGood for prototypes

Connection Modes

Strict (default)Loose
Source → Target onlyAny handle → any handle
Predictable behaviorMore flexible
Use for data flowsUse for diagrams
tsx
<ReactFlow connectionMode={ConnectionMode.Loose} />

Edge Rendering

Default edgesCustom edges
Fast renderingMore control
Limited stylingAny SVG/HTML
Simple use casesComplex labels

Source and attribution

Source:existential-birds/beagleinplugins/beagle-react/skills/react-flow-architectureat commitd1a7489

License: No license

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal