Documentation Index Fetch the complete documentation index at: https://docs.velt.dev/llms.txt
Use this file to discover all available pages before exploring further.
The @veltdev/reactflow-crdt library enables real-time collaborative editing on React Flow diagrams. The collaboration editing engine is built on top of Yjs and Velt SDK.
Prerequisites
Node.js (v14 or higher)
React (v16.8 or higher for hooks)
A Velt account with an API key (sign up )
Optional: TypeScript for type safety
Setup
Step 1: Install Dependencies
Install the required packages:
npm install @veltdev/reactflow-crdt @veltdev/react
Step 2: Setup Velt
Initialize the Velt client by following the Velt Setup Docs . This is required for the collaboration engine to work.
Step 3: Initialize Velt CRDT Extension
Initialize the Velt CRDT extension and use it to initialize the React Flow diagram.
Pass an editorId to uniquely identify each diagram instance you have in your app. This is especially important when you have multiple diagrams in your app.
const { nodes , edges , onNodesChange , onEdgesChange , onConnect } = useVeltReactFlowCrdtExtension ({
editorId: 'YOUR_EDITOR_ID' ,
initialNodes: [{ id: '1' , data: { label: 'Start' }, position: { x: 0 , y: 0 } }],
initialEdges: []
});
return (
< ReactFlow
nodes = { nodes }
edges = { edges }
onNodesChange = { onNodesChange }
onEdgesChange = { onEdgesChange }
onConnect = { onConnect }
fitView
>
< Background />
</ ReactFlow >
);
Notes
Unique editorId : Use a unique editorId per diagram instance.
Use CRDT handlers : Always apply the store-provided nodes, edges, onNodesChange, onEdgesChange, and onConnect.
Testing and Debugging
To test collaboration:
Login two unique users on two browser profiles and open the same page in both.
Move nodes or create connections in one window and verify they sync in the other.
Common issues:
Nodes/edges not syncing: Ensure each diagram has a unique editorId and the Velt client is initialized. Also ensure that you are logged in with two different users in two different browser profiles.
No updates on connect: Use the provided CRDT-aware nodes, edges, onNodesChange/onEdgesChange and onConnect handlers from the store.
Complete Example
React / Next.js
Live Demo
Open Live Demo In Larger Window | View Demo Repo import {
Background ,
ReactFlow ,
ReactFlowProvider ,
useReactFlow ,
type Edge
} from '@xyflow/react' ;
import { useCallback , useRef } from 'react' ;
import { useVeltInitState } from '@veltdev/react' ;
import { useVeltReactFlowCrdtExtension } from '@veltdev/reactflow-crdt' ;
import '@xyflow/react/dist/style.css' ;
const initialNodes = [
{
id: '0' ,
type: 'input' ,
data: { label: 'Node' },
position: { x: 0 , y: 50 },
},
];
const initialEdges : Edge [] = [];
let id = 9 ;
const getId = () => ` ${ id ++ } ` ;
const nodeOrigin : [ number , number ] = [ 0.5 , 0 ];
const AddNodeOnEdgeDrop = () => {
const { nodes , edges , onNodesChange , onEdgesChange , onConnect } = useVeltReactFlowCrdtExtension ({
editorId: 'YOUR_EDITOR_ID' ,
initialEdges ,
initialNodes ,
});
const reactFlowWrapper = useRef ( null );
const { screenToFlowPosition } = useReactFlow ();
const onConnectEnd = useCallback (
( event : any , connectionState : any ) => {
if ( ! connectionState . isValid ) {
const id = getId ();
const { clientX , clientY } = 'changedTouches' in event ? event . changedTouches [ 0 ] : event ;
const newNode = {
id ,
position: screenToFlowPosition ({ x: clientX , y: clientY }),
data: { label: `Node ${ id } ` },
origin: [ 0.5 , 0.0 ],
};
// Add new node using CRDT-aware change handler
onNodesChange ([{ type: 'add' , item: newNode }]);
// Add new edge using CRDT-aware change handler
const newEdge = {
id ,
source: connectionState . fromNode . id ,
target: id ,
};
onEdgesChange ([{ type: 'add' , item: newEdge }]);
}
},
[ screenToFlowPosition , onNodesChange , onEdgesChange ],
);
return (
< div className = "react-flow-container" ref = { reactFlowWrapper } >
< ReactFlow
style = { { backgroundColor: "#F7F9FB" } }
nodes = { nodes }
edges = { edges }
onNodesChange = { onNodesChange } // CRDT-synced node changes
onEdgesChange = { onEdgesChange } // CRDT-synced edge changes
onConnect = { onConnect } // CRDT-synced connections
onConnectEnd = { onConnectEnd } // Custom handler for adding nodes/edges
fitView
fitViewOptions = { { padding: 2 }
}
nodeOrigin = { nodeOrigin }
>
< Background />
</ ReactFlow >
</ div >
);
};
function ReactFlowComponent () {
const veltInitialized = useVeltInitState ();
if ( ! veltInitialized ) {
return < div > Loading... </ div > ;
}
return (
< ReactFlowProvider >
< AddNodeOnEdgeDrop />
</ ReactFlowProvider >
);
}
export default ReactFlowComponent ;
See all 99 lines
APIs
Custom Encryption
You can encrypt CRDT data before it’s stored in Velt by registering a custom encryption provider. For CRDT methods, input data is of type Uint8Array | number[].
React / Next.js
Other Frameworks
async function encryptData ( config : EncryptConfig < number []>) : Promise < string > {
const encryptedData = await yourEncryptDataMethod ( config . data );
return encryptedData ;
}
async function decryptData ( config : DecryptConfig < string >) : Promise < number []> {
const decryptedData = await yourDecryptDataMethod ( config . data );
return decryptedData ;
}
const encryptionProvider : VeltEncryptionProvider < number [], string > = {
encrypt: encryptData ,
decrypt: decryptData ,
};
< VeltProvider
apiKey = "YOUR_API_KEY"
encryptionProvider = { encryptionProvider }
/>
async function encryptData ( config : EncryptConfig < number []>) : Promise < string > {
const encryptedData = await yourEncryptDataMethod ( config . data );
return encryptedData ;
}
async function decryptData ( config : DecryptConfig < string >) : Promise < number []> {
const decryptedData = await yourDecryptDataMethod ( config . data );
return decryptedData ;
}
const encryptionProvider : VeltEncryptionProvider < number [], string > = {
encrypt: encryptData ,
decrypt: decryptData ,
};
client . setEncryptionProvider ( encryptionProvider );
See also: setEncryptionProvider()
· VeltEncryptionProvider
· EncryptConfig
· DecryptConfig
Provides real-time collaborative editing on React Flow diagrams with Yjs and Velt SDK.
Signature: useVeltReactFlowCrdtExtension(config: VeltReactFlowCrdtExtensionConfig)
Params: VeltReactFlowCrdtExtensionConfig
editorId: Unique identifier for the diagram instance.
initialNodes: Initial set of nodes.
initialEdges: Initial set of edges.
debounceMs: Debounce time for update propagation (ms).
Returns: VeltReactFlowCrdtExtensionResponse
store: React Flow CRDT store instance.
nodes: Array of nodes in the diagram.
edges: Array of edges in the diagram.
onNodesChange: CRDT-aware handler to apply node changes.
onEdgesChange: CRDT-aware handler to apply edge changes.
onConnect: CRDT-aware handler to apply connect changes.
setNodes: Method to set nodes
setEdges: Method to set edges
CRDT-aware handler to apply node changes (add/update/remove) that sync across collaborators.
onNodesChange ([{ type: 'add' , item: newNode }]);
CRDT-aware handler to apply edge changes (add/update/remove) that sync across collaborators.
onEdgesChange ([{ type: 'add' , item: newEdge }]);
CRDT-aware connect handler compatible with React Flow’s <ReactFlow onConnect={...} />.
< ReactFlow onConnect = { onConnect } />
Imperative setter for nodes (useful for non-event updates). Synced via the store.
setNodes ( prev => [ ... prev , myNode ]);
Imperative setter for edges (useful for non-event updates). Synced via the store.
setEdges ( prev => [ ... prev , myEdge ]);