Quick Start
Get started with @statelyai/graph in under 5 minutes.Create Your First Graph
Create a graph
const graph = createGraph({
nodes: [
{ id: 'a', label: 'Start' },
{ id: 'b', label: 'Middle' },
{ id: 'c', label: 'End' },
],
edges: [
{ id: 'e1', sourceId: 'a', targetId: 'b' },
{ id: 'e2', sourceId: 'b', targetId: 'c' },
],
});
Mutate the graph
// Add a new node
addNode(graph, { id: 'd', label: 'Shortcut' });
// Add an edge
addEdge(graph, { id: 'e3', sourceId: 'a', targetId: 'd' });
addEdge(graph, { id: 'e4', sourceId: 'd', targetId: 'c' });
Working Example
Here’s a complete example you can run:import {
createGraph,
addNode,
addEdge,
getNode
} from '@statelyai/graph';
import {
getShortestPath,
bfs,
isAcyclic
} from '@statelyai/graph/algorithms';
import { getNeighbors } from '@statelyai/graph/queries';
// Create a simple task dependency graph
const graph = createGraph({
nodes: [
{ id: 'design', label: 'Design UI' },
{ id: 'implement', label: 'Implement' },
{ id: 'test', label: 'Test' },
{ id: 'deploy', label: 'Deploy' },
],
edges: [
{ id: 'e1', sourceId: 'design', targetId: 'implement' },
{ id: 'e2', sourceId: 'implement', targetId: 'test' },
{ id: 'e3', sourceId: 'test', targetId: 'deploy' },
],
});
// Check if the graph is a valid DAG (no cycles)
console.log(isAcyclic(graph)); // true
// Get all tasks that depend on 'design'
const dependents = getNeighbors(graph, 'design');
console.log(dependents.map(n => n.label)); // ['Implement']
// Find the path from start to finish
const path = getShortestPath(graph, {
from: 'design',
to: 'deploy'
});
console.log('Task order:');
console.log(path.source.label); // 'Design UI'
path.steps.forEach(step => {
console.log('→', step.node.label);
});
// Output:
// Task order:
// Design UI
// → Implement
// → Test
// → Deploy
// Traverse all tasks in order
for (const node of bfs(graph, 'design')) {
console.log('Process:', node.label);
}
Hierarchical Graphs
Nodes can have parent-child relationships for compound graphs:import { createGraph, flatten } from '@statelyai/graph';
import { getChildren, getParent } from '@statelyai/graph/queries';
const graph = createGraph({
nodes: [
{ id: 'app' },
{ id: 'auth', parentId: 'app', initialNodeId: 'login' },
{ id: 'login', parentId: 'auth' },
{ id: 'signup', parentId: 'auth' },
{ id: 'dashboard', parentId: 'app' },
],
edges: [
{ id: 'e1', sourceId: 'login', targetId: 'dashboard' },
{ id: 'e2', sourceId: 'signup', targetId: 'dashboard' },
],
});
// Query the hierarchy
const authChildren = getChildren(graph, 'auth');
console.log(authChildren.map(n => n.id)); // ['login', 'signup']
const parent = getParent(graph, 'login');
console.log(parent?.id); // 'auth'
// Flatten compound nodes into a flat graph
const flat = flatten(graph);
console.log(flat.nodes.map(n => n.id)); // ['login', 'signup', 'dashboard']
flatten() resolves hierarchical edges: edges targeting a compound node resolve to its initialNodeId, and edges from a compound node expand from all leaf descendants.Visual Graphs
Create graphs with guaranteed position and size properties for rendering:import { createVisualGraph } from '@statelyai/graph';
const diagram = createVisualGraph({
direction: 'right',
nodes: [
{
id: 'start',
x: 0,
y: 0,
width: 120,
height: 60,
shape: 'ellipse',
label: 'Start'
},
{
id: 'end',
x: 200,
y: 0,
width: 120,
height: 60,
shape: 'ellipse',
color: '#3b82f6',
label: 'End'
},
],
edges: [
{
id: 'e1',
sourceId: 'start',
targetId: 'end',
x: 0,
y: 0,
width: 100,
height: 100
}
],
});
// All nodes and edges have x, y, width, height
console.log(diagram.nodes[0].x); // 0 (guaranteed to exist)
console.log(diagram.direction); // 'right'
Format Conversion
Convert between different graph formats:import { createGraph } from '@statelyai/graph';
import { toCytoscapeJSON } from '@statelyai/graph/cytoscape';
import { toD3Graph } from '@statelyai/graph/d3';
import { toDOT } from '@statelyai/graph/dot';
import { toGraphML } from '@statelyai/graph/graphml';
const graph = createGraph({
nodes: [{ id: 'a' }, { id: 'b' }],
edges: [{ id: 'e1', sourceId: 'a', targetId: 'b' }],
});
// Export to visualization libraries
const cytoData = toCytoscapeJSON(graph);
const d3Data = toD3Graph(graph);
// Export to text formats
const dot = toDOT(graph);
console.log(dot);
// digraph {
// "a"
// "b"
// "a" -> "b"
// }
const graphml = toGraphML(graph);
// Returns GraphML XML string
import { toCytoscapeJSON, fromCytoscapeJSON } from '@statelyai/graph/cytoscape';
// Export to Cytoscape.js
const cytoData = toCytoscapeJSON(graph);
// Import from Cytoscape.js
const graph = fromCytoscapeJSON(cytoData);
Type Safety with Custom Data
Attach strongly-typed data to nodes and edges:interface TaskData {
assignee: string;
estimatedHours: number;
status: 'todo' | 'in-progress' | 'done';
}
interface DependencyData {
type: 'blocks' | 'relates-to';
}
const graph = createGraph<TaskData, DependencyData>({
nodes: [
{
id: 'task-1',
label: 'Design',
data: {
assignee: 'Alice',
estimatedHours: 8,
status: 'done'
}
},
{
id: 'task-2',
label: 'Implement',
data: {
assignee: 'Bob',
estimatedHours: 16,
status: 'in-progress'
}
},
],
edges: [
{
id: 'e1',
sourceId: 'task-1',
targetId: 'task-2',
data: { type: 'blocks' }
},
],
});
// Full type inference
const task = getNode(graph, 'task-1');
if (task) {
console.log(task.data.assignee); // string
console.log(task.data.status); // 'todo' | 'in-progress' | 'done'
}
Common Queries
Explore graph structure with query functions:import {
getNeighbors,
getDegree,
getSources,
getSinks
} from '@statelyai/graph/queries';
// Get all connected nodes
const neighbors = getNeighbors(graph, 'a');
// Get number of connected edges
const degree = getDegree(graph, 'a');
// Get nodes with no incoming edges
const sources = getSources(graph);
// Get nodes with no outgoing edges
const sinks = getSinks(graph);
Next Steps
Hierarchical Graphs
Learn about parent-child relationships
Graph Algorithms
Explore pathfinding, traversal, and analysis
Format Converters
Convert between different graph formats
Queries
Discover graph query functions