graph
pggraph : Graph database capabilities for PostgreSQL
Overview
| ID | Extension | Package | Version | Category | License | Language |
|---|---|---|---|---|---|---|
| 2630 | graph
|
pggraph
|
1.0.0 |
FEAT
|
Apache-2.0
|
Rust
|
| Attribute | Has Binary | Has Library | Need Load | Has DDL | Relocatable | Trusted |
|---|---|---|---|---|---|---|
--s-d--
|
No
|
Yes
|
No
|
Yes
|
no
|
no
|
| Relationships | |
|---|---|
| See Also | age
pg_liquid
onesparse
pgrdf
ltree
sparql
|
PGXN distribution and package are pggraph; installed extension name is graph.
Packages
| Type | Repo | Version | PG Major Compatibility | Package Pattern | Dependencies |
|---|---|---|---|---|---|
| EXT | PIGSTY
|
1.0.0 |
18
17
16
15
14
|
pggraph |
- |
| RPM | PIGSTY
|
1.0.0 |
18
17
16
15
14
|
pggraph_$v |
- |
| DEB | PIGSTY
|
1.0.0 |
18
17
16
15
14
|
postgresql-$v-pggraph |
- |
| Linux / PG | PG18 | PG17 | PG16 | PG15 | PG14 |
|---|---|---|---|---|---|
el8.x86_64
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
el8.aarch64
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
el9.x86_64
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
el9.aarch64
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
el10.x86_64
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
el10.aarch64
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
d12.x86_64
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
d12.aarch64
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
d13.x86_64
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
d13.aarch64
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
u22.x86_64
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
u22.aarch64
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
u24.x86_64
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
u24.aarch64
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
u26.x86_64
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
u26.aarch64
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
PIGSTY 1.0.0
|
Source
pig build pkg pggraph; # build rpm/debInstall
Make sure PGDG and PIGSTY repo available:
pig repo add pgsql -u # add both repo and update cacheInstall this extension with pig:
pig install pggraph; # install via package name, for the active PG version
pig install graph; # install by extension name, for the current active PG version
pig install graph -v 18; # install for PG 18
pig install graph -v 17; # install for PG 17
pig install graph -v 16; # install for PG 16
pig install graph -v 15; # install for PG 15
pig install graph -v 14; # install for PG 14Create this extension with:
CREATE EXTENSION graph;Usage
Sources:
- pgGraph v1.0.0 README
- v1.0.0 release notes
- SQL API Reference
- Schema Registration
- Administration and Security
- v0.1.8 to v1.0.0 migration guide
pggraph is the package and PGXN distribution name, but the installed PostgreSQL extension is graph. The extension builds derived graph artifacts from ordinary PostgreSQL tables, keeps those tables as the source of truth, and exposes graph search, traversal, shortest path, GQL-style reads, and selected mapped writes through the graph schema.
v1.0.0 is the first production release. It supports PostgreSQL 14-18, named graphs, graph-scoped grants and quotas, durable synchronization, bounded traversal and analytics, maintenance jobs, and selected GQL read/write profiles. It does not claim full ISO GQL, full openCypher, or a public SQL/PGQ GRAPH_TABLE surface. Standard PostgreSQL SQLSTATEs are paired with stable PGxxx details for application diagnostics.
Basic Graph Build
CREATE EXTENSION IF NOT EXISTS graph;
SELECT graph.reset();
CREATE TABLE companies (
id text PRIMARY KEY,
name text NOT NULL
);
CREATE TABLE people (
id text PRIMARY KEY,
name text NOT NULL,
company_id text REFERENCES companies(id)
);
INSERT INTO companies VALUES
('c1', 'Acme Bank'),
('c2', 'Northwind Trading');
INSERT INTO people VALUES
('p1', 'Alice', 'c1'),
('p2', 'Bob', 'c1'),
('p3', 'Carol', 'c2');
SELECT * FROM graph.auto_discover('public');
SELECT * FROM graph.build();
SELECT node_count, edge_count, edge_types
FROM graph.status();graph.auto_discover('public') scans primary keys and foreign keys in the selected schema, registers discovered source tables and edges, and prepares the graph for graph.build(). In production schemas, prefer explicit registration so labels, search columns, filter columns, weights, tenant behavior, and graph identity are deliberate.
Manual and Named-Graph Registration
SELECT graph.create_graph('customer_360', namespace := 'analytics');
SELECT graph.set_current_graph('customer_360', namespace := 'analytics');
SELECT graph.add_table(
table_name := 'public.people'::regclass,
id_column := 'id',
columns := ARRAY['name'],
tenant_column := NULL
);
SELECT graph.add_table_to_graph(
graph_name := 'customer_360',
table_name := 'public.companies'::regclass,
id_column := 'id',
columns := ARRAY['name'],
graph_namespace := 'analytics'
);
SELECT graph.add_edge_to_graph(
graph_name := 'customer_360',
from_table := 'public.people'::regclass,
from_column := 'company_id',
to_table := 'public.companies'::regclass,
to_column := 'id',
label := 'works_at',
bidirectional := true,
graph_namespace := 'analytics'
);
SELECT * FROM graph.build_graph('customer_360', graph_namespace := 'analytics');Registration applies to the current graph selection unless you use the explicit *_to_graph and *_from_graph helpers. Node identifiers must match a primary key or a unique NOT NULL index. columns controls searchable and GQL-visible properties; traversal filter pushdown uses separate graph.add_filter_column() registrations. Edge-table and junction-table relationships are also supported, and label_column can provide dynamic edge labels within the documented public limit.
Search, Traversal, and Paths
SELECT node_table_name, node_id, node
FROM graph.search(
property_key := 'name',
property_value := 'Alice',
table_filter := 'public.people'::regclass,
mode := 'exact',
hydrate := true
);
SELECT depth, node_table_name, node_id, edge_path
FROM graph.traverse(
'public.people'::regclass,
'p1',
2,
hydrate := false
);
SELECT step, node_table_name, node_id, edge_label
FROM graph.shortest_path(
'public.people'::regclass,
'p1',
'public.companies'::regclass,
'c1',
hydrate := false
);With hydrate := false, graph functions return compact graph coordinates. With hydration enabled, PostgreSQL source-table ACLs and RLS still govern which source rows are visible. Stale coordinates fail closed rather than fabricating rows.
GQL Queries and Relationship Writes
SELECT row
FROM graph.gql(
'MATCH (p:people)-[:works_at]->(c:companies)
WHERE p.name = $name
RETURN p.id AS person_id, c.name AS company
ORDER BY company',
params := '{"name":"Alice"}'::jsonb,
hydrate := true
);graph.gql() returns one jsonb object per SQL row. Node labels map to registered table names and relationship types map to registered edge labels. The supported mutable GQL profile includes registered relationship creation: mapped writes still go through PostgreSQL source-table DML, and source tables remain authoritative. Unsupported openCypher or SQL/PGQ shapes fail with explicit capability errors instead of partial behavior.
Administration and Operations
GRANT USAGE, CREATE ON SCHEMA graph TO graph_admin;
SELECT * FROM graph.grant_graph('customer_360', 'app_reader', 'read', namespace := 'analytics');
SELECT * FROM graph.set_graph_quota('owner', 'max_named_graphs', 25, scope_key := 'app_owner');
SELECT * FROM graph.select_graph('customer_360', namespace := 'analytics');
SELECT * FROM graph.add_sync_policy('customer_360', schedule_interval_secs := 300, graph_namespace := 'analytics');
SELECT * FROM graph.run_due_jobs();
SELECT * FROM graph.projection_status();Graph administration covers catalog mutation, builds, sync replay, maintenance, quotas, runtime graph loading, and global analytics. Named graph privileges are read, write, build, and admin, but graph read is not enough by itself: hydrated reads still require SELECT on source tables. A selected graph tenant also scopes traversal, search, GQL, and Cypher calls unless an explicit matching tenant is supplied.
Migrating from the Alpha Release
The v0.1.8 to v1.0.0 transition is source-preserving but is not an in-place catalog or binary update. Back up and test a restore, inventory registrations and dependents, stop graph writers and schedulers, then preflight the drop in a transaction:
BEGIN;
DROP EXTENSION graph;
ROLLBACK;After reviewing every dependent object, remove the alpha extension, install v1.0.0, reapply only reviewed public registration calls, and rebuild from the PostgreSQL source tables:
DROP EXTENSION graph CASCADE;
CREATE EXTENSION graph VERSION '1.0.0';
-- Reapply graph.add_table(...), graph.add_edge(...), and related calls.
SELECT * FROM graph.build();
SELECT * FROM graph.status();CASCADE can remove application views, functions, generated synchronization objects, and other dependents. Alpha catalogs, .pggraph files, manifests, and projection segments are not v1.0.0 portable state. Rollback requires restoring the tested backup with the matching alpha package, then rebuilding its graph state.
Caveats
- Source tables remain the source of truth. Graph artifacts, projection files, sync state, and runtime engines are derived and rebuildable.
- Use
graph.build()or graph-scoped build helpers after registration changes, and use sync/maintenance APIs when relying on incremental projection state. - Internal catalog tables such as
graph._graphs, grants, quotas, jobs, sync logs, and projection metadata are implementation details; use public SQL functions instead. - v1.0.0 uses Rust 1.96 and
cargo-pgrx0.19.1 for source builds. PostgreSQL 14 through 18 are supported upstream, with PostgreSQL 17 as the default release-gate target.