Skip to content
statelyaiPublic

About

Universal utilities for working with graphs

Resources

Code of conduct

Contributing

Stars

249 stars

Watchers

1 watching

Forks

Latest commit

 

History

186 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@statelyai/graph

Graphs as plain JSON, with the algorithms, formats, and layout engines to do real work with them.

A graph is just { nodes, edges } data, and every operation is a standalone, tree-shakable function. Built and used by Stately to power its visual tooling for complex systems.

Documentation

Why @statelyai/graph?

  • Your graph is just data. No class instances, no import/export step. Save it with JSON.stringify(), diff it, or send it to a worker as-is; lookups are indexed transparently.
  • One model for real diagrams. Directed and undirected edges (even mixed), nested nodes, named ports, and positions and sizes: what node editors, statecharts, and architecture diagrams need, and most graph libraries leave out.
  • Fast. Fastest in most of our cross-library benchmarks against graphology, ngraph, graphlib, and cytoscape. For example, it builds a 100k-node graph 9–15× faster than graphology.
  • Algorithms you can trust. Shortest paths, centrality, communities, flow, matching, isomorphism, and more. Every query and algorithm is tested against edge cases such as self-loops, parallel edges, and unknown ids, and algorithms are iterative, so deep graphs won't overflow the stack.
  • Works with your tools. Convert to and from graph and diagram formats including Graphviz DOT, Mermaid, GraphML, D2, React Flow, and Cytoscape. Lay out with 8 engines, including ELK, dagre, and Graphviz. Turn XState machines into graphs. Each adapter is an optional subpath import.
  • Typed end to end. Generic data types for nodes, edges, ports, and the graph itself.

Installation

npm install @statelyai/graph

Quick start

Create a publishing workflow and find the shortest route from draft to published:

import { createGraph, getShortestPath } from '@statelyai/graph';

const graph = createGraph({
  nodes: [
    { id: 'draft' },
    { id: 'review' },
    { id: 'published' },
  ],
  edges: [
    { id: 'submit', sourceId: 'draft', targetId: 'review' },
    { id: 'approve', sourceId: 'review', targetId: 'published' },
  ],
});

const path = getShortestPath(graph, { from: 'draft', to: 'published' });

if (path) {
  console.log([path.source.id, ...path.steps.map(({ node }) => node.id)]);
  // ['draft', 'review', 'published']
}

Format preservation

The table describes bare Graph converters. Format mappings, Graph round-tripping, native semantics and source preservation are separate contracts. No converter currently guarantees 100% losslessness for arbitrary Graphs or complete native documents. Selected-field tests characterize supported mappings; they do not establish conformance to an entire format.

Formats Graph → format → Graph Native → Graph → native Source details
Adjacency list, Cytoscape, D3, DOT, ELK, GEXF, GML, GraphML, JGF, TGF, xyflow Partial Partial None
CSV/TSV, Graphology export JSON, Graphlib JSON, NetworkX node-link JSON, adjacency matrix, Matrix Market, Graphviz JSON, draw.io, Pajek, scoped PlantUML Partial Partial None
GraphSON3 typed TinkerGraph objects, DGML, CX2, RDF1.1 dataset/syntax profiles Partial Partial Partial scoped sources
Edge list Partial Full for endpoint tuples None
D2 Partial Partial Partial comments
Mermaid architecture, block, C4, class, ER, flowchart, GitGraph, ishikawa, mindmap, requirement, Sankey, sequence, state, UseCase Partial Partial Partial annotations

Graph preservation includes JSON-serializable fields, optional-field presence and entity order. Native preservation includes format-specific topology, attributes and semantics. Source preservation additionally covers comments, declaration order, spelling and whitespace. Adapter metadata can carry selected Graph fields without making them native features. Use a GraphDocument when those details matter.

Additional adapters: adjacency matrix, Matrix Market, Graphviz JSON, draw.io, Pajek, PlantUML, GraphSON, DGML, CX2, RDF.

import { getFormatSupportEntry } from '@statelyai/graph/format-support';

const support = getFormatSupportEntry('graphml');
console.log(support?.preservation); // { graph: 'partial', native: 'partial', document: 'none' }

The existing features API remains available; features.roundTrip describes the legacy Graph round-trip assessment. preservation is optional for third-party entries and present on every built-in entry.

Native imports now retain supported key/default/namespace semantics, edge modes, weights, hierarchy, ports and structured metadata. DOT declarations and clusters, ELK endpoint identity, JGF versions, D2 source abstractions and Mermaid ordered sequence events, properties and entity declarations have dedicated regression coverage. Canonical and visible native edits take precedence over unchanged source hints where the adapter can resolve the mapping.

Source-only annotations remain a separate limitation: diagram comments, frontmatter and directives may be reformatted; XML/DOT comments and complete declaration order are not guaranteed. Unsupported Graph topology such as hyperedges is rejected instead of silently truncated. Independent native validators cover selected emitted profiles. Broader structural source editing remains bounded by each document adapter.

Native documents

import { graphMLDocumentConverter } from '@statelyai/graph/graphml';

const document = graphMLDocumentConverter.from(xml);
const persisted = JSON.parse(JSON.stringify(document));
const exactSource = graphMLDocumentConverter.to(persisted);

CSV/TSV use explicit node and edge tables with a serializable schema; default optional cells encode JSON, including visible labels. Graphology, Graphlib and NetworkX subpaths convert their native JSON profiles without runtime library dependencies. Mapping limits: CSV/TSV, Graphology, Graphlib, NetworkX.

GraphSON uses an explicit typed TinkerGraph object profile; DGML and CX2 preserve scoped native declarations. RDF maps subject/object terms to nodes and statements to directed edges, retaining predicate and graph terms. The dependency-free /rdf dataset API is separate from optional N3-backed /rdf/syntax. These domain mappings reject incompatible Graph state rather than guessing.

Every native converter subpath offers a *DocumentConverter registration. The @statelyai/graph/document factory also accepts explicit custom codecs, including VisualGraph codecs. Documents retain exact original text/native JSON values on no-op export, including comments, extensions and unsupported constructs, after JSON persistence. Projection can be partial or unavailable and carries explicit diagnostics. This guarantees source retention, not full semantic interpretation.

Ambiguous source identity edits reject when generated IDs cannot establish correspondence; matching private lineage does not override live native identity.

Supported Graph edits patch native source and must pass reparse proof. Unsupported or conflicting edits throw instead of replaying stale source. Native source edits remain authoritative when Graph is unchanged. Regeneration is an explicit, diagnostic-bearing operation that reports differing Graph fields after reparse, as well as possible source loss. See document API for the validated JSON domain and editing boundary.

Native validation

pnpm test:native runs pinned native parsers, compilers, schemas and runtime oracles on Node 24. pnpm test:coverage enforces measured converter coverage floors. These tools are dev-only; ordinary core tests still cover Node 20/22/24. Selected native assertions supplement conversion regressions without promising complete language coverage. See native validation.

Optional peer dependencies

The core (@statelyai/graph) and the pure-JSON formats have no runtime dependencies. Each adapter subpath that wraps a third-party library declares it as an optional peer dependency, so you only install the ones you use. If the peer isn't installed, importing that subpath throws a module-resolution error for the peer — install it and the import works.

Subpath import Peer dependency to install
@statelyai/graph/dot dotparser
@statelyai/graph/drawio fflate, fast-xml-parser
@statelyai/graph/graphml, @statelyai/graph/gexf fast-xml-parser
@statelyai/graph/layout/cytoscape cytoscape
@statelyai/graph/xstate xstate
@statelyai/graph/layout/elk elkjs
@statelyai/graph/layout/dagre @dagrejs/dagre
@statelyai/graph/layout/d3-force d3-force
@statelyai/graph/layout/d3-hierarchy d3-hierarchy
@statelyai/graph/layout/graphviz @hpcc-js/wasm-graphviz
@statelyai/graph/layout/forceatlas2 graphology, graphology-layout-forceatlas2
@statelyai/graph/layout/webcola webcola
@statelyai/graph/schemas (Zod schemas) zod

For example, the /dot converter (toDOT, fromDOT, dotConverter) needs dotparser:

npm install @statelyai/graph dotparser

For guides, API details, and adapter dependencies, see the docs. To contribute, see CONTRIBUTING.md.

Inspiration

Inspired by NetworkX, Graphology, and graphlib.

License

MIT

About

Universal utilities for working with graphs

Resources

Code of conduct

Contributing

Stars

249 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages