pgGraph: graph queries on ordinary PostgreSQL tables
Open-source graph database superpowers for your existing Postgres data.
At a glance
- What is it?
- pgGraph is a PostgreSQL extension that builds a derived graph index over tables you already have and exposes traversal, shortest path and relationship search from SQL. The interesting part is what it refuses to do: no separate store, no new query language, and no ownership of your data.
- Who is it for?
- Adopt pgGraph if your graph questions are hop-limited and your data already lives in PostgreSQL tables you are unwilling to migrate. Do not adopt it if you need unbounded traversal depth, a Cypher-style language, or a graph store that exists independently of the relational schema.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 9 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 2, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The recursive SQL you keep rewriting
Every team with a relational schema eventually writes the same recursive CTE. Find records related to Alice within two hops. Find the shortest path between this person and this company. The README frames the problem exactly that way: graph-style questions "often require custom recursive SQL for each schema." That sentence is the whole pitch, and it is a fair one. The recursion is not hard to write once. It is hard to write correctly for every table pair, and it is hard to keep correct when a foreign key changes.
pgGraph targets the engineer who already has PostgreSQL in production and does not want a second database. The README is explicit that "your tables stay the source of truth" and that pgGraph "builds a derived graph index" queried through functions in the graph schema. That is the audience: teams whose entities are already rows, whose edges are already foreign keys, and whose graph questions are bounded. It is not aimed at people who need a graph engine as the primary store.
A derived index over tables you already own
The architecture follows from one constraint: PostgreSQL tables remain authoritative. pgGraph does not copy your rows into a graph-shaped storage layer. It reads registered tables, discovers relationships between them, and materialises an index that the graph schema functions query.
The quickstart description in the README spells out the sequence: it "creates two normal PostgreSQL tables, discovers the foreign key relationship, builds the graph, and runs example queries." So foreign keys are the edge source, at least in the demo path. The index is derived, which means it can be rebuilt, and it means a query that reads it is reading a snapshot rather than the live tables. The README does not document how stale the index can become between rebuilds, nor what happens to a traversal issued mid-rebuild. That is a gap worth knowing about before you put this behind a latency-sensitive endpoint.
The extension is written in Rust and built with pgrx, which is why the Dockerfile pins PGRX_VERSION=0.19.1 and runs cargo pgrx package rather than a plain make install. The Makefile comments explain the consequence for anyone building from source: pgrx requires the active pgNN feature to match the pg_config major, "otherwise the default (pg17) is built and install fails on any other major." That is a real footgun. If you build against PostgreSQL 16 and forget the feature flag, you get a compile that succeeds and an install that fails.
Installing pgGraph with Homebrew, Docker or cargo pgrx
There are three documented paths. The convenience channel for a local PostgreSQL 17 install is the Evokoa Homebrew tap. The README gives these commands, and the formula "installs pgGraph 1.2.0 from the signed release bundle":
brew tap Evokoa/tap
brew install pggraph
brew test pggraphAfter that, start the server and create the extension. The extension name is graph, not pggraph, which is worth noting because the two names are easy to confuse when you are reading commands quickly:
brew services start postgresql@17
psql -d postgres -c "CREATE EXTENSION graph;"
psql -d postgres -c "SELECT extname, extversion FROM pg_extension WHERE extname = 'graph';"The second query should return one row naming the graph extension and its version. If it returns nothing, the extension was not created and the rest of the tutorial will fail with function-not-found errors.
The second path is the repository quickstart, which builds a disposable PostgreSQL 17 image and runs a full demo. You need Docker running first.
git clone https://github.com/evokoa/pggraph.git
cd pggraph
scripts/quickstart.shThe script has modes. The default builds Postgres, loads demo data and runs example graph queries. There is also setup, which installs the extension without loading a sample graph, and psql, which prepares demo data and opens a client. To install into a container you already run, the README shows a mode taking a container name, major version, database and user:
scripts/quickstart.sh docker my-postgres 17 appdb postgresThe third path is a source build against a local PostgreSQL using pgrx:
scripts/quickstart.sh pgrxUnderneath, that delegates to cargo pgrx install. The Makefile target passes --no-default-features --features $(PG_FEATURE), where PG_FEATURE is derived from the pg_config major. If you invoke cargo pgrx directly instead of through the script or the Makefile, you are responsible for setting that feature yourself.
The README also documents a playground mode that starts a Streamlit interface with a preset dataset and a mode of csr or mutable, for example scripts/quickstart.sh playground panama csr. The README does not explain what distinguishes csr from mutable beyond the names, so treat that as an experiment rather than a documented interface.
Where the derived index stops being the right answer
The design has a boundary, and it is the index. Because the graph is derived from registered tables, anything that changes the shape of those tables invalidates work. Add a foreign key you want traversed and the graph has to be rebuilt to see it. The README documents no incremental rebuild path and no rollback procedure, so the operational question of what a rebuild costs on a large table set is unanswered in the published documentation.
The second limitation is depth. pgGraph is built for the queries the README names: within N hops, shortest path between two nodes, search across registered tables. Those are bounded questions. If your workload is genuinely open-ended traversal across millions of nodes with variable depth and you need the graph engine to be the system of record, a derived index over relational tables is the wrong shape. You would be paying rebuild cost to approximate a store that does that natively.
The third is language. pgGraph deliberately avoids a new query language, which the README presents as a benefit. It is a benefit for adoption and a cost for expressiveness. Complex pattern matching that a dedicated graph query language expresses in one clause becomes a composition of SQL functions plus whatever filtering you wrap around them. Whether that is acceptable depends entirely on how many of your queries are the three named shapes versus something more elaborate.
pgGraph against a standalone graph database
The obvious alternative is a dedicated graph database. The difference is not performance, it is where the data lives and who writes it. A standalone graph store owns the entities and the edges. Loading means a pipeline from PostgreSQL into that store, and keeping it current means that pipeline runs forever. You get native traversal, a graph query language, and index structures built for adjacency rather than derived from foreign keys. You also get a second system to operate, back up and reconcile.
pgGraph inverts that. The relational tables stay authoritative, so there is no sync problem and no divergence to reconcile. The cost is that graph capability is a derived artifact with a rebuild lifecycle. For a team whose graph questions are secondary to their relational workload, that trade is straightforward. For a team whose product is the graph, it is backwards.
There is also a managed option. The README notes that Evokoa "launched a managed version of pgGraph on polygres.com" for GraphRAG workloads, and the repository homepage points at the same domain. That is a hosted path rather than an alternative technology, but it is the answer if you want the extension's behaviour without running the rebuild and maintenance yourself.
Maintenance, licensing and what you are actually taking on
The repository is not archived, and the last push was on 2026-08-22, the same day v1.2.0 was released. That release is titled "pgGraph Open-Vocabulary Relationship Types," and it follows v1.1.0 on 2026-08-16, which covers caller-scoped RLS and safe replacement, and v1.0.0 on 2026-07-25, the production release. Three releases in roughly a month is a fast cadence. It also means the surface is still moving, and an extension that changes relationship-type semantics between minor versions is one you should pin rather than float.
Upgrade cost has two parts. The extension itself upgrades through the normal PostgreSQL extension mechanism, but the derived index is the part that matters operationally, because a rebuild is the expensive step and the README does not document an incremental path. Budget for rebuild time proportional to your registered table set, and test the rebuild against a production-sized copy before you rely on it.
On licensing, the situation needs care. The README badge and the Dockerfile label both say Apache-2.0, but the repository metadata reports NOASSERTION, which means the automated licence detection could not classify the LICENSE file. Those two facts disagree. Read LICENSE yourself and confirm the terms before you redistribute the extension or bake it into an image you ship. This is not a legal opinion, just a note that the two signals in the repository do not match.
Editorial conclusion
Adopt pgGraph if your graph questions are hop-limited and your data already lives in PostgreSQL tables you are unwilling to migrate. Do not adopt it if you need unbounded traversal depth, a Cypher-style language, or a graph store that exists independently of the relational schema. Before committing, verify that the extension loads on your PostgreSQL major, that the graph index rebuilds within your maintenance window, and that the licence terms in LICENSE match your distribution plans.
Frequently asked questions
Does pgGraph replace my PostgreSQL tables?
No. The README states that your tables stay the source of truth and that pgGraph builds a derived graph index queried through functions in the graph schema.
Which PostgreSQL versions does pgGraph support?
The README badge lists PostgreSQL 14 to 18, and the Dockerfile builds against PostgreSQL 17 by default. The Makefile notes that the pgrx feature flag must match the pg_config major or the install fails.
How do I install pgGraph on macOS?
The README documents the Evokoa Homebrew tap: brew tap Evokoa/tap, then brew install pggraph. The formula installs pgGraph 1.2.0 from the signed release bundle, and you then create the graph extension in a database.
What is the Docker image for pgGraph?
The README gives the signed multi-architecture release image as ghcr.io/evokoa/pggraph:1.2.0 and advises verifying its published digest before deployment.
Official sources
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.
[](https://hysenlabs.com/projects/evokoa-pggraph)