The Problem

PostgreSQL handles relational queries well, but graph-style questions—"find records within 2 hops," "shortest path between two nodes"—require hand-written recursive SQL per schema. pgGraph solves this by building a derived graph index over ordinary Postgres tables, so you query graphs with SQL functions in the graph schema rather than maintaining a separate graph database.

What This Does

pgGraph is a PostgreSQL extension (Rust, 111 files under graph/src/) that adds graph traversal, shortest-path, and relationship queries to existing tables. Your tables stay the source of truth; pgGraph maintains the index and syncs it via triggers (graph/src/sql_sync.rs). It ships with a Docker image, a sandbox playground (sandbox/playground/app.py, Python/Flask), and a benchmark suite (sandbox/benchmark/).

The repo is a collection of four projects: the core extension (graph/), shell scripts for build/fuzz (scripts/), the Python sandbox, and Docker init. The core extension is the substantial piece.

How It Is Wired

Execution starts at execute in graph/src/bfs.rs:224, which reaches 58 functions and is called from 55 places. From there, the call graph (5,826 edges) routes through reset_and_create_fixtures (201 callers) and insert (129 callers)—these carry the widest blast radius. with_panic_boundary (121 callers) wraps error handling across the codebase.

Key files by responsibility:

  • graph/src/sql_facade/admin.rs — 202 functions, the admin surface; called from 31 files.
  • graph/src/engine.rs — 120 functions, 9 types; the query engine core.
  • graph/src/persistence.rs — 103 functions; owns file I/O (writes graph files).
  • graph/src/query/value.rs — 107 functions; row projection and relationship handling.
  • graph/src/sql_sync.rs — 77 functions; trigger installation and sync logic.

The code touches the filesystem in 15 functions (persistence, projection chunks/manifests) and makes one outbound network call. No import cycles exist among the 13 internal modules.

How To Use It

# Clone and build (Docker is the fastest path)
git clone https://github.com/moses-y/pgGraph
cd pgGraph
docker compose up -d

# Or build the extension directly
make build

Configuration is minimal—the docker-compose.yml and docker/init/01-create-extensions-and-schedule.sql handle setup. The README documents pulling the pre-built image from ghcr.io/evokoa/pggraph. The playground runs via sandbox/playground/app.py (Flask). The Makefile provides build targets; no environment variables are documented beyond standard Postgres connection settings.

Real-World Use

A fraud-detection system where transactions live in Postgres tables. Register accounts and transactions as graph nodes/edges, then query:

-- Find accounts within 2 hops of a flagged account
SELECT * FROM graph.search(
  'MATCH (a:account)-[:transaction*1..2]->(b) WHERE a.id = 123 RETURN b.id'
);

The trigger-based sync keeps the graph current as transactions insert, so no ETL pipeline or separate database is needed.

Code Health & Issues

Static analysis found 92 issues (27 high, 65 medium). The main concerns:

  • High — Deep nestinggraph/src/builder.rs, graph/src/path_finder.rs: max indentation depth 9; control flow is hard to follow. Fix with early returns.
  • High — Duplicated code — 548 repeated 6-line blocks across 96 files. Extract shared helpers.
  • High — Oversized filesgraph/src/catalog/graphs.rs, engine.rs, persistence.rs (1,402 lines). Split by responsibility.
  • High — CI doesn't run tests — 44 test files exist, no test command in .github/workflows/release.yml.
  • High — Unpinned GitHub Actions@v3/@v5 tags in workflows; pin to commit SHAs.
  • Medium — No dependency update bot — 4 manifests, no Dependabot/Renovate config.
  • Medium — Docker runs as root — no USER directive in Dockerfile.
  • Medium — Low test coverage — 4 test files against 121 source files (ratio 0.033).

The Bottom Line

The core extension is well-structured with real engineering—Rust, proper persistence, sync triggers. The main risks are CI that doesn't run its tests and deep nesting in hot paths. Use it if you need graph queries on Postgres without a separate database; fix the CI test gap before trusting a green check.