Documentation Index
Fetch the complete documentation index at: https://crystalflow.dev/docs/llms.txt
Use this file to discover all available pages before exploring further.
Get started with CrystalFlow’s visual workflow builder in 5 minutes.
This guide is for building visual workflow applications with React. For backend-only workflows, see Core-Only Quick Start.
Prerequisites
- Node.js 18+ installed
- React 18+ project set up
- Basic React knowledge
Step 1: Install Packages
npm install @crystalflow/react @crystalflow/core @crystalflow/types reflect-metadata
Add to your tsconfig.json:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"target": "ES2020",
"lib": ["ES2020", "DOM"]
}
}
Step 3: Create Nodes
Create a few simple nodes:
import { Node, defineNode, Input, Output } from '@crystalflow/core';
@defineNode({
type: 'math.add',
label: 'Add Numbers',
category: 'Math'
})
export class AddNode extends Node {
@Input({ type: 'number', label: 'A' })
a: number = 0;
@Input({ type: 'number', label: 'B' })
b: number = 0;
@Output({ type: 'number', label: 'Result' })
result: number;
execute() {
this.result = this.a + this.b;
}
}
src/nodes/NumberInputNode.ts
import { Node, defineNode, Property, Output } from '@crystalflow/core';
@defineNode({
type: 'input.number',
label: 'Number Input',
category: 'Input'
})
export class NumberInputNode extends Node {
@Property({
type: 'number',
label: 'Value',
defaultValue: 0
})
value: number = 0;
@Output({ type: 'number', label: 'Value' })
output: number;
execute() {
this.output = this.value;
}
}
import { Node, defineNode, Input } from '@crystalflow/core';
@defineNode({
type: 'output.display',
label: 'Display',
category: 'Output'
})
export class DisplayNode extends Node {
@Input({ type: 'any', label: 'Value' })
value: any = null;
execute() {
console.log('Result:', this.value);
}
}
export { NumberInputNode } from './NumberInputNode';
export { AddNode } from './AddNode';
export { DisplayNode } from './DisplayNode';
Step 4: Create Workflow Component
import React from 'react';
import 'reflect-metadata';
import { WorkflowBuilder } from '@crystalflow/react';
import { NumberInputNode, AddNode, DisplayNode } from './nodes';
import 'reactflow/dist/style.css';
function App() {
const nodes = [NumberInputNode, AddNode, DisplayNode];
const handleExecute = (result) => {
if (result.status === 'success') {
console.log('✅ Workflow executed successfully!');
console.log('Duration:', result.duration, 'ms');
} else {
console.error('❌ Workflow failed:', result.error);
}
};
return (
<div style={{ width: '100vw', height: '100vh' }}>
<WorkflowBuilder
nodes={nodes}
onExecute={handleExecute}
showNodePalette={true}
showPropertyPanel={true}
showToolbar={true}
/>
</div>
);
}
export default App;
Step 5: Run Your App
Open your browser and you should see:
Using the Visual Builder
Add Nodes
Drag nodes from the left palette onto the canvas, or click to add at center.
Connect Nodes
Drag from output handles (right side) to input handles (left side) to create connections.
Configure Properties
Click a node to select it, then edit its properties in the right panel.
Execute Workflow
Click the ▶️ Execute button in the toolbar to run your workflow.
View Results
Check the browser console to see execution results.
Example Workflow
Try building this simple calculator:
- Add two Number Input nodes (set values to 5 and 3)
- Add one Add node
- Add one Display node
- Connect: Number Input 1 → Add (port A)
- Connect: Number Input 2 → Add (port B)
- Connect: Add (Result) → Display (Value)
- Click Execute - Console shows:
Result: 8
What You Get
Node Palette
Browse and add nodes by category with search
Visual Canvas
Drag, drop, and connect nodes visually
Property Panel
Edit node properties and configurations
Toolbar Actions
Execute, save, load, and clear workflows
Save & Load Workflows
The toolbar provides save/load functionality:
<WorkflowBuilder
nodes={nodes}
onWorkflowChange={(workflow) => {
// Auto-save to localStorage
localStorage.setItem('workflow', JSON.stringify(workflow.toJSON()));
}}
showToolbar={true}
/>
Load on mount:
const [initialWorkflow, setInitialWorkflow] = useState(null);
useEffect(() => {
const saved = localStorage.getItem('workflow');
if (saved) {
const workflowData = JSON.parse(saved);
setInitialWorkflow(Workflow.fromJSON(workflowData));
}
}, []);
return <WorkflowBuilder initialWorkflow={initialWorkflow} nodes={nodes} />;
Customize the Builder
Control which panels are visible:
<WorkflowBuilder
nodes={nodes}
showNodePalette={true} // Show/hide left panel
showPropertyPanel={true} // Show/hide right panel
showToolbar={true} // Show/hide top toolbar
editorMode="visual" // 'visual' | 'json' | 'split'
className="my-builder" // Custom CSS class
style={{ height: '800px' }} // Custom height
/>
Next Steps
Build Your First App
Complete tutorial with custom nodes
Creating Custom Nodes
Learn to build powerful nodes
Workflow Builder Guide
Master the visual builder
Examples
See complete examples
Troubleshooting
Make sure experimentalDecorators: true is in your tsconfig.json and you’ve imported 'reflect-metadata' at the top of your entry file.
Nodes not showing in palette?
Ensure all node classes are passed to the nodes prop and have the @defineNode decorator.
Import React Flow styles: import 'reactflow/dist/style.css' in your component.
Verify target: "ES2020" and lib: ["ES2020", "DOM"] in your tsconfig.json.