Skip to main content

Quick Start

Get started with @statelyai/graph in under 5 minutes.

Create Your First Graph

1

Import the library

import { createGraph, addNode, addEdge } from '@statelyai/graph';
2

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' },
  ],
});
3

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' });
4

Run algorithms

import { getShortestPath } from '@statelyai/graph/algorithms';

const path = getShortestPath(graph, { from: 'a', to: 'c' });
console.log(path.steps.map(s => s.node.id)); // ['d', 'c'] - takes the shortcut!

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

Build docs developers (and LLMs) love