# franken-networkx ports NetworkX to Rust and measures every path against a pinned 3.6.1

> A graph library whose selling point is not speed but refused drift: iteration order, tie-breaks, exception classes and error wording are treated as contract, checked by a parity suite of about 1,100 files and by running NetworkX's own suite with the Rust code behind it. The drop-in surface is complete for declared paths, and the README is careful to call it incomplete overall.

**Dicklesworthstone/franken_networkx** — Memory-safe clean-room Rust reimplementation of NetworkX with deterministic graph semantics, differential conformance, and RaptorQ-backed durability.

- Repository: https://github.com/Dicklesworthstone/franken_networkx
- Stars: 26 · Forks: 4
- Language: Python
- License: NOASSERTION
- Published: 2026-08-24 · Updated: 2026-08-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/dicklesworthstone-franken-networkx

## Two ways in: a standalone library, or a networkx>=3.0 backend

The library can be consumed two ways, and the difference matters for how you debug a call site. In standalone mode you use the familiar NetworkX API on the library's own graph types. In backend mode you wire it in as a backend for networkx 3.0 or newer, and supported calls dispatch into Rust without changing the calling code. Either way the graph types are the same four core classes the reference library uses, and the declared import and signature surface is measured against a pinned NetworkX 3.6.1 feature universe, where the current result records 4,129 strictly present paths out of 4,129 applicable, with none partial and none missing. The classifier behind that number rejects shapes declared only through signature or module metadata, on classes and on functions alike, so the count reflects real definitions rather than declared ones. The library describes itself as a measured, incomplete drop-in surface, and that framing is deliberate.

## Tie-breaks become an explicit policy instead of an accident of hashing

Where NetworkX leaves tie-break behavior implicit, this project makes it explicit through a policy with thirteen variants, and the storage layer underneath is an insertion-order preserving map rather than nested dictionaries. That combination is what lets an algorithm that could return several equally valid answers be pinned to one reproducible outcome instead of depending on hash layout. The same instinct shows up in return types: where NetworkX hands back a generator, this library hands back a generator rather than a list with a different representation, and where NetworkX would raise a TypeError from indexing a dict with an unhashable key, the same exception class is raised here. Serialization round-trip behavior is part of that contract too, which is why graph mutation semantics and error message wording sit alongside iteration order in the list of things held fixed.

## NetworkX's own test suite runs with fnx behind it, and one test drops out

The strongest check in the project is running the upstream project's test suite against this implementation as the backend. The recorded result, dated 24 September 2026, is 6,815 tests passing with zero failures and zero errors, against 6,816 passing on plain NetworkX 3.6.1. The gap is not a silent hole: 80 tests are skipped under this backend where plain NetworkX skips 78 and marks one as expected failure, so one test moves out of the passing column. That floor is pinned in a ratchet file under the upstream suite artifacts with no allowed failures recorded, and the quality run fails on any failure against it. Everything else follows the same pattern of measured rather than asserted parity, with exception class and error wording compared call by call across thousands of fixtures.

## 313 algorithms are registered for dispatch, and each run leaves a Blake3 receipt

Backend dispatch is a registry rather than a guess: 313 algorithms are registered in the backend module, which is the set of calls that will actually reach Rust in backend mode. Around that sits the audit machinery. Every algorithm execution gets a complexity witness, and those witnesses are recorded in a length-prefixed Blake3 ledger of decision paths, which turns behavioral parity into something you can regression-lock rather than spot-check. Parsing has the same treatment, handled by a policy engine that is mode aware and fails closed by default rather than guessing. Durability artifacts are written as erasure-coded sidecars with decode-proof receipts. Alongside the Rust side, a Python parity suite of about 1,100 files compares this library against the reference call by call, and the quality run executes it in guarded shards through a dedicated script, recording 68,318 passing and zero failing on 24 September 2026.

## The quality gate is one command that chains nine stages

Instead of a project's ordinary continuous integration, the gate is a single tool invocation with a name and a target flag. It runs in order: formatting, checking, clippy with warnings promoted to errors, the Rust tests across the workspace crates including conformance fixture replay, a fuzz smoke pass over the fuzz targets, documentation and examples and coverage drift checks, generated report checks, the upstream NetworkX suite, and finally the full Python parity suite. Any stage can stop the run. The fuzzing side is not a single target either: there are 33 cargo-fuzz binaries spread across parsers and algorithm families, and the smoke stage touches all of them. Two configuration files back this up in the repository root, one for the Python linter and one for pre-commit, and the coverage matrix under the documentation directory is regenerated and drift-checked on every run, so a change to the export list or a signature fails the gate rather than waiting to be noticed.

## ABI3 wheels avoid the Rust toolchain for five platform targets

Installing does not require a Rust toolchain. Prebuilt ABI3 wheels are published on the Python package index for Linux on both x86_64 and aarch64, including a musllinux build, for macOS on x86_64 and arm64, and for Windows on x86_64, all covering Python 3.10 and newer. Source builds remain available for developers who are modifying the Rust internals, and the package metadata declares Python 3.10 through 3.13 as supported versions, with a development status of beta and a typing marker. The declared runtime dependencies are the reference library at version 3.0 or newer and numpy at 1.24 or newer, which is the first thing to check before swapping an implementation: the backend mode adds a real dependency rather than replacing one. Build configuration comes from the Python package index side using the maturin backend.

```
pip install franken-networkx
```

## The release profile trades build time for cross-crate inlining

The workspace is organized as a set of member crates covering classes, views, dispatch, conversion, algorithms, generators, reading and writing, durability, conformance, the runtime, the tie-break engine, and the Python bindings. The manifest names the 2024 edition, the license file, and the release version. Two things in the release profile are deliberate. Link-time optimization is set to thin and the code generation unit count to one, because the stock Cargo defaults leave cross-crate inlining off and the hot kernels here call across crate boundaries constantly. The accompanying note is careful about what that changes: the optimization is described as semantics preserving, with IEEE floating point behaviour untouched by any fast math mode, so results stay identical and only the machine code improves. A second profile inherits those settings for performance work and keeps line table debug info while disabling symbol stripping.

## Why a port and not a subclass, a wrapper, or a clean-slate Rust API

The project spells out the three approaches it rejects and why. Subclassing or monkey-patching the reference graphs with C or Cython adjacency only replaces isolated hot loops: the nested dictionaries still dominate memory and cache behavior, the algorithm-level work stays in Python, and the GIL stays held. Wrapping a separate Rust or C++ engine and copying data in and out makes the conversion the entire workload for short algorithms, loses attribute fidelity, diverges on tie-breaks, and leaves algorithm coverage sparse. Rewriting in Rust with a Rust-idiomatic API forces users to rewrite their code, hides the behavioral oracle, and lets iteration order drift make results non-portable. The chosen design is the opposite of all three: port the algorithms, preserve observable behavior on implemented paths, and measure every declared path against the pinned reference.

## Conclusion

Take it when a NetworkX workload has outgrown pure Python and you cannot afford to rewrite call sites, and when you can accept an adapter on top of NetworkX plus numpy. Read the coverage document before you commit, since the project itself frames the surface as measured and incomplete, and treat the upstream ratchet file as the contract you would be held to. Two cautions: one upstream test is skipped more often under this backend than under plain NetworkX, and anything already skipped stays skipped, so verify your own algorithms against the 313 registered dispatch entries rather than assuming parity from the headline number.

## FAQ

### What is NetworkX and what is it used for?

NetworkX is described here as the canonical Python graph library, rich and correct but slow on anything that is not toy sized, because its pure-Python adjacency, Python-level inner loops, and per-call dictionary bookkeeping turn graph analytics over graphs of a hundred thousand to a million nodes into multi-minute affairs. franken-networkx is the Rust-backed replacement for that workload.

### What language is NetworkX written in, and what language is franken-networkx?

NetworkX is pure Python, which is why the global interpreter lock cannot be released during heavy work. franken-networkx is written in Rust using the 2024 edition with unsafe code forbidden, and it wraps that work in call sites that release the GIL.

### What are the key differences between Neo4j and NetworkX?

This repository draws no comparison with Neo4j. The comparisons it does make are against three other approaches to speeding up NetworkX: patching the graphs with C or Cython adjacency, wrapping a separate Rust or C++ engine, and rewriting in Rust with a Rust-idiomatic API, each rejected for a stated reason.

## Sources

- [Official README](https://github.com/Dicklesworthstone/franken_networkx#readme)
- [Project repository](https://github.com/Dicklesworthstone/franken_networkx)
- [Release notes](https://github.com/Dicklesworthstone/franken_networkx/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/dicklesworthstone-franken-networkx
