Library / SDK
davecom/SwiftGraph avatar
davecom/SwiftGraph

SwiftGraph: a graph data structure with the algorithms already written

A Graph Library for Swift

814 stars83 forksSwiftApache-2.0

At a glance

What is it?
SwiftGraph is a Swift implementation of a graph structure with weighted, unweighted, directed and undirected variants, generics over both vertex and weight types, and a set of classic algorithms including breadth-first search, depth-first search, Dijkstra, minimum spanning tree and cycle detection. It targets every platform Swift supports, Linux included.
Who is it for?
SwiftGraph suits a Swift developer who needs breadth-first search, Dijkstra, a minimum spanning tree or topological sort over typed vertices and weights, and it is the wrong choice for graph visualisation, layout or large-scale analytics, since it is a data structure with algorithms attached and nothing else.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly Swift, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A graph structure first, algorithms second

SwiftGraph is a Swift implementation of a graph data structure, and it is written to work on every platform Swift supports, which the project names as iOS, macOS and Linux, and it is tested on GNU/Linux.

The design choice that matters most is generics over both axes. The vertex type and the weight type are parameters, so the same implementation serves a graph of city names with integer distances and a graph of custom objects with double weights. The library covers weighted and unweighted graphs, directed and undirected ones, and it names the family of graph types explicitly: WeightedGraph, with a String vertex and an Int weight, is the example that runs through the documentation.

The algorithms are the second half. The library ships breadth-first search, depth-first search and Dijkstra's algorithm, plus utility functions for topological sort, Jarnik's algorithm to find a minimum spanning tree, detecting a directed acyclic graph, and enumerating all cycles. The repository topics list breadth-first-search, depth-first-search, dijkstra-algorithm, prims-algorithm and topological-sort.

The audience is a developer who needs a graph in a Swift project and does not want to write the algorithms, or a student or educator who wants readable Swift with heavy documentation. The library is by Dave Kopec, the licence is Apache-2.0, and the last push to the repository was on 2026-10-18, with the listed release 4.0.0 published on 2026-03-05.

Vertices are addressed by index, and edges are Codable

Two details in the design shape everything you write against the library.

First, edges refer to vertices by their index in the graph, and that index is an integer. The Edge protocol documentation is explicit: an edge is a connection between two vertices in the graph, and the vertices are specified by their index. This is not an implementation detail leaking out, it is the model, and it is why the performance tips in the documentation are about index lookups.

Second, all edges must be Codable. That is a hard requirement stated in the protocol documentation, and it means the edge type can take part in serialisation, though the vertex type carries no such requirement, so persisting a whole graph still needs work for the vertices.

The vertex type itself is unconstrained. The documentation describes the Edge protocol as the contract that all edges in a graph must conform to, and the vertex type parameter sits alongside it, which is what allows a graph of city names and a graph of your own domain objects to use the same algorithms.

Four ways to add it, one of them a copy and paste

Installation is the least remarkable part of the project and, for once, completely unambiguous.

Swift Package Manager is the first option and the instruction is to use the repository as your dependency, with a Package.swift at the top of the tree. CocoaPods is the second, and the pod is named SwiftGraph. Carthage is the third, and it needs a Cartfile entry:

bash
github "davecom/SwiftGraph" ~> 4.0

The manual option is the fourth, and it is worth noting because it is unusual to still see it: copy all of the sources in the Sources folder into your project. For a library that is Apache-2.0 licensed, that is legally straightforward, and for a team that does not want a package manager dependency it works, at the cost of owning the copy.

The version floor is the other thing to check before you plan the integration. The compatibility table is long because the library has been carried across many Swift generations. SwiftGraph 3.0 and above requires Swift 5, which means Xcode 10.2. SwiftGraph 2.0 is for Swift 4.2 with Xcode 10.1, 1.5.1 for Swift 4.1 with Xcode 9, 1.4.1 for Swift 3 with Xcode 8, 1.0.6 for Swift 2 with Xcode 7, and 1.0.0 for Swift 1.2 with Xcode 6.3.

In other words, a modern project takes 4.0 and an old one has a choice of six older lines, and the Cartfile constraint of ~> 4.0 is the modern one.

The result shapes are not what you would guess

The algorithms are standard, but the way their results come back is worth reading before you build on them.

Dijkstra's algorithm returns a tuple of a distances array and a path dictionary, and the documentation shows what you then do with them. You convert the distance array into a dictionary keyed by vertex name, and you convert the path dictionary into an ordered list of edges with a separate helper, then turn those edges into vertex names with another:

swift
let (distances, pathDict) = cityGraph.dijkstra(root: "New York", startDistance: 0)
var nameDistance: [String: Int?] = distanceArrayToVertexDict(distances: distances, graph: cityGraph)
swift
let path: [WeightedEdge<Int>] = pathDictToPath(from: cityGraph.indexOfVertex("New York")!, to: cityGraph.indexOfVertex("San Francisco")!, pathDict: pathDict)
let stops: [String] = cityGraph.edgesToVertices(edges: path)

So a shortest path comes back as raw structures that you assemble with two or three calls. That is a deliberate trade: the library hands you the intermediate representation and lets you decide what to do with it, and the indexOfVertex calls are forced unwrapped in the example, which is a reminder that the lookup is O(n) and returns an optional.

The other algorithms return simpler things. The minimum spanning tree is one call, the cycles are another, and the acyclicity check is a property:

swift
let mst = cityGraph.mst()
swift
let cycles = cityGraph.detectCycles()
swift
let isADAG = cityGraph.isDAG

Searches come in a filtering form too. findAllBfs takes a start vertex and a closure, and returns every vertex the breadth-first search reaches that satisfies the predicate, which in the example is every city whose name begins with S.

Index lookups are O(n), and the advice is to insert by index

The tips section of the documentation is short, and two of the items are about the same underlying cost.

Looking for the index of a vertex is O(n) time, where n is the number of vertices in the graph. That is inherent in the index-based edge model, and it means that building a graph by adding edges with vertex objects, where each edge has to look up the index of its endpoints, pays that cost repeatedly.

The mitigation the documentation gives is direct: inserting an edge by vertex indices is much faster than inserting an edge by vertex objects that need to have their indices looked up. If you are constructing a large graph, you resolve the indices once and insert by index.

The other two tips are about learning the library. To get a sense of how to use SwiftGraph, read the unit tests. And a sample Mac app that implements the Nine Tails problem is included in the repository, with the instruction to change the target of the project to SwiftGraphSampleApp to build it.

The Nine Tails sample is a good marker of the intended audience. It is a small, self-contained puzzle, the kind of thing that shows a graph search in a form you can watch run, and it doubles as a check that the library builds in your environment before you wire it into anything.

The documentation is in the source, and the HTML version is generated

Documentation is unusually prominent for a library of this size, and it comes in two forms.

The primary form is in-source documentation written with the latest Apple documentation technique, so that alt-clicking a method name in Xcode gives you the details. The README describes this as a large amount of documentation in the source code, and for a data structure library that is the right place for it, since the semantics of a graph API live in the API itself.

The secondary form is generated HTML documentation, produced with Jazzy, published at davecom.github.io/SwiftGraph. There is a generate_docs.sh script at the top of the repository and a docs directory, so the published site is regenerated from the source rather than written by hand.

The repository layout reflects a library that predates the current packaging norms and has kept up with them. Alongside Package.swift there is SwiftGraph.podspec for CocoaPods, an Xcode project, a Tests directory, a SwiftGraphSampleApp directory, a CHANGELOG.md, a CONTRIBUTORS.md, a BuildScripts directory and a .travis.yml file, which dates the continuous integration configuration to the era when Travis was the common choice.

A README section also walks through the component types, starting with Edges: the Edge protocol, the integer index addressing, and the Codable requirement, with more component overviews following in the same style.

Where a graph library stops and something else begins

The scope of SwiftGraph is a data structure and a set of classic algorithms, and the boundaries matter for anyone expecting more.

There is no graph visualisation, no layout engine and no rendering. There is no query language, no persistence layer beyond the Codable requirement on edges, and no distributed or parallel implementation. If what you want is to draw a force-directed graph, or query a graph of a hundred million edges, or run analytics across a cluster, this library is not the tool and its feature list will not tempt you, because it does not pretend to be.

The alternative approaches split into two. One is to build the structure yourself over a dictionary of adjacency lists and implement the handful of traversals you need, which for breadth-first and depth-first search is perhaps a page of code, and which leaves the weight and vertex typing to Swift generics in the same way. The other is to adopt a framework that treats the graph as a first-class object with visualisation and layout, which gives you far more surface area and takes over the model.

The difference in approach is that SwiftGraph gives you the algorithms in a typed, tested, documented form and leaves the representation to you, while doing the traversal correctly is the part people usually get wrong. The trade is that the API is more manual at the edges, with the result of dijkstra needing three helper calls before it is a list of stops, and the index model making bulk construction the caller's problem to optimise.

The version history is a fair summary of the project. Six lines spanning Swift 1.2 to Swift 5, one listed release in 2026, and a repository that was pushed to on 2026-10-18.

Editorial conclusion

SwiftGraph suits a Swift developer who needs breadth-first search, Dijkstra, a minimum spanning tree or topological sort over typed vertices and weights, and it is the wrong choice for graph visualisation, layout or large-scale analytics, since it is a data structure with algorithms attached and nothing else. Verify first that version 4.0 matches your toolchain, since the library only supports Swift 5 and newer and earlier Swift versions need the old 1.x and 2.x lines, and read the shape of the results before you adopt the API, since dijkstra returns a distance array and a path dictionary that you convert yourself.

Frequently asked questions

How do I add SwiftGraph to a Swift project?

Use Swift Package Manager by adding the repository as a dependency, use the CocoaPod named SwiftGraph, or add github "davecom/SwiftGraph" ~> 4.0 to your Cartfile for Carthage. There is also a manual option of copying the sources in the Sources folder into your project.

Which Swift versions does SwiftGraph support?

SwiftGraph 3.0 and above requires Swift 5 with Xcode 10.2. Older lines exist for Swift 4.2 with 2.0, Swift 4.1 with 1.5.1, Swift 3 with 1.4.1, Swift 2 with 1.0.6, and Swift 1.2 with 1.0.0. The library also supports GNU/Linux and is tested on it.

What does dijkstra() return in SwiftGraph?

It returns a tuple of a distances array and a path dictionary. You convert the distances into a dictionary keyed by vertex with distanceArrayToVertexDict, and the path dictionary into an ordered list of edges with pathDictToPath, then into vertex names with edgesToVertices.

Which graph algorithms does SwiftGraph include?

Breadth-first search and depth-first search through bfs(), dfs() and findAllBfs, Dijkstra's algorithm, a minimum spanning tree through mst() using Jarnik's algorithm, topological sort, directed acyclic graph detection through isDAG, and cycle enumeration through detectCycles().

Is SwiftGraph suitable for very large graphs?

The documentation states that looking for the index of a vertex is O(n) in the number of vertices, and recommends inserting edges by vertex indices rather than by vertex objects, since that avoids repeated index lookups. Any bulk construction should follow that advice.

Official sources

  1. davecom/SwiftGraph on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/davecom-swiftgraph.svg)](https://hysenlabs.com/projects/davecom-swiftgraph)

Was this useful?