A Clojure graph library that uses JGraphT. You build graphs over plain Clojure values, run JGraphT's algorithms, and get plain Clojure data back.
Python's networkx is slow because it is pure Python. Graph algorithms are
irregular and they chase pointers, so they do not vectorize into a C core as
numpy workloads do. On the JVM the same algorithms run on JIT-compiled code with
real threads.
loom and ubergraph are pure-Clojure graph libraries. Use one of them if it
covers your needs. cljgrapht uses a different approach. It does not write the
algorithms in Clojure. It wraps JGraphT and puts a
Clojure API in front of the JGraphT algorithm catalog (shortest paths,
centrality, flow, matching, coloring, isomorphism, and more). Use cljgrapht when
you want an algorithm that the pure-Clojure libraries do not have, or when you
want JGraphT's performance on large graphs. A vertex can be any Clojure value.
Results come back as vectors, sets, and maps.
This is a performance wrapper, not a persistent data structure. Graphs are JGraphT's native mutable objects. Constructors and mutators return the graph so that you can thread calls, but they mutate the graph in place.
Requires JDK 11+ (JGraphT 1.5.x).
tools.deps (deps.edn):
net.clojars.savya/cljgrapht {:mvn/version "1.1.2"}
Leiningen (project.clj):
[net.clojars.savya/cljgrapht "1.1.2"]
Run tests with clojure -M:test. Build a jar with clojure -T:build jar and
deploy to Clojars with clojure -T:build deploy.
(require '[cljgrapht.core :as g]
'[cljgrapht.algo :as a])
;; Build a weighted directed graph from edge data.
(def road
(g/weighted-digraph [[:a :b 1.0] [:a :c 4.0] [:b :c 1.0] [:c :d 1.0]]))
;; Cheapest route, as Clojure data.
(a/shortest-path road :a :d)
;; => {:path [:a :b :c :d] :weight 3.0}
;; Undirected social graph; who is most central?
(def social (g/graph [[:alice :bob] [:bob :carol] [:bob :dave] [:carol :dave]]))
(a/betweenness-centrality social)
;; => {:alice 0.0 :bob 2.0 :carol 0.0 :dave 0.0}
;; Dependency graph: order tasks, or detect a cycle.
(def deps (g/digraph [[:compile :test] [:compile :package] [:test :deploy]
[:package :deploy]]))
(a/topological-sort deps) ;; => [:compile :test :package :deploy]
(a/cycle? deps) ;; => false
cljgrapht.algoshortest-path, shortest-path-length, astar,
bellman-ford, bellman-ford-distances,
all-pairs-shortest-path-length, johnson-all-pairs,
k-shortest-paths, all-simple-pathsconnected-components, strongly-connected-components,
connected?, strongly-connected?topological-sort, dag?, cycle?,
vertices-on-cycles, simple-cyclesminimum-spanning-treemaximum-matching (Edmonds), maximum-weight-matching
(Kolmogorov blossom V), bipartite-matching (Hopcroft-Karp),
bipartite?, bipartite-setsmax-flow, min-cut (push-relabel; edge weights are capacities)coloring (DSatur default; :greedy, :largest-degree-first,
:smallest-degree-last via :algorithm), greedy-coloringlink-prediction-score and
predict-linkslca and lca-set with naive and rooted variantssteiner-treeline-graph, including optional edge-weight conversionmaximum-density-subgraph with caller-provided sentinelsbetweenness-centrality, closeness-centrality, pagerankmaximal-cliques, clustering-coefficient,
global-clustering-coefficient, coreness, density,
isolated-vertices, isomorphic?cljgrapht.gencomplete-graph, ring-graph, star-graph,
grid-graphgnp-random-graph, barabasi-albert-graph,
watts-strogatz-graphcljgrapht.iodot, write-dot!, read-dotgraphml, write-graphml!cljgrapht.loom extends loom's Graph,
Digraph, WeightedGraph, and EditableGraph protocols to raw
org.jgrapht.Graph, so loom's generic algorithms (loom.alg) run directly on
cljgrapht graphs:
(require '[cljgrapht.core :as g]
'[cljgrapht.loom] ;; load the protocol extensions
'[loom.alg :as alg])
(def gr (g/weighted-digraph [[:a :b 1.0] [:a :c 10.0] [:b :c 1.0]]))
(alg/dijkstra-path gr :a :c) ;; => (:a :b :c)
Loom is not a dependency of cljgrapht. Add a loom artifact
(net.clojars.savya/loom or aysylu/loom) to your own deps before you require
cljgrapht.loom. Loom's EditableGraph operations mutate the underlying
JGraphT graph in place and return the same instance. Loom's persistent graph
records behave differently.
These benchmarks use random weighted digraphs and
criterium quick-bench. They use
Clojure 1.12.5 and JDK 17. They exclude graph construction from the algorithm
rows. Source: bench/bench.clj.
2,000 vertices / ~10k edges
| Task | loom 1.0.2 | ubergraph 0.9.0 | cljgrapht |
|---|---|---|---|
| Build from edge list | 201 ms | 27 ms | 4.7 ms |
| Weighted shortest path (Dijkstra) | 7.3 ms | 5.2 ms | 0.27 ms |
| Connected components | 6.0 ms | 22 ms | 1.9 ms |
10,000 vertices / ~50k edges
| Task | loom 1.0.2 | ubergraph 0.9.0 | cljgrapht |
|---|---|---|---|
| Build from edge list | 963 ms | 182 ms | 27 ms |
| Weighted shortest path (Dijkstra) | 20 ms | 8.1 ms | 1.1 ms |
| Connected components | 28 ms | 95 ms | 13 ms |
This is the tradeoff of a native Java engine. loom and ubergraph use persistent, immutable graphs. cljgrapht uses mutable graphs instead. Use cljgrapht when graph size or algorithm depth is the constraint.
Copyright © 2026 Savyasachi
Distributed under the Eclipse Public License 2.0, the same license JGraphT is available under.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |