PostgreSQL: Property Graphs

mpweiher1 pts0 comments

PostgreSQL: Documentation: 19: 5.15. Property Graphs

June 4, 2026:<br>PostgreSQL 19 Beta 1 Released!

Documentation &rarr; PostgreSQL 19

Development Versions:

19

devel

This documentation is for an unsupported version of PostgreSQL.

You may want to view the same page for the<br>current<br>version, or one of the other supported versions listed above instead.

5.15. Property Graphs

Prev<br>Up<br>Chapter 5. Data Definition<br>Home<br>Next

5.15. Property Graphs #

A property graph is a way to represent database contents, as an alternative to the usual (in SQL) approach of representing database contents using relational structures such as tables. A property graph can then be queried using graph pattern matching syntax, instead of join queries typical of relational databases. PostgreSQL implements SQL/PGQ[6], which is part of the SQL standard, where a property graph is defined as a kind of read-only view over relational tables. So the actual data is still in tables or table-like objects, but is exposed as a graph for graph querying operations. (This is in contrast to native graph databases, where the data is stored directly in a graph structure.) Underneath, both relational queries and graph queries use the same query planning and execution infrastructure, and in fact relational and graph queries can be combined and mixed in single queries.

A graph is a set of vertices and edges. Each edge has two distinguishable associated vertices called the source and destination vertices. (So in this model, all edges are directed.) Vertices and edges together are called the elements of the graph. A property graph extends this well-known mathematical structure with a way to represent user data. In a property graph, each vertex or edge has one or more associated labels, and each label has zero or more properties. The labels are similar to table row types in that they define the kind of the contained data and its structure. The properties are similar to columns in that they contain the actual data. In fact, by default, a property graph definition exposes the underlying tables and columns as labels and properties, but more complicated definitions are possible.

Consider the following table definitions:

CREATE TABLE products (<br>product_no integer PRIMARY KEY,<br>name varchar,<br>price numeric<br>);

CREATE TABLE customers (<br>customer_id integer PRIMARY KEY,<br>name varchar,<br>address varchar<br>);

CREATE TABLE orders (<br>order_id integer PRIMARY KEY,<br>ordered_when date<br>);

CREATE TABLE order_items (<br>order_items_id integer PRIMARY KEY,<br>order_id integer REFERENCES orders (order_id),<br>product_no integer REFERENCES products (product_no),<br>quantity integer<br>);

CREATE TABLE customer_orders (<br>customer_orders_id integer PRIMARY KEY,<br>customer_id integer REFERENCES customers (customer_id),<br>order_id integer REFERENCES orders (order_id)<br>);

When mapping this to a graph, the first three tables would be the vertices and the last two tables would be the edges. The foreign-key definitions correspond to the fact that edges link two vertices. (Graph definitions work more naturally with many-to-many relationships, so this example is organized like that, even though one-to-many relationships might be used here in a pure relational approach.)

Here is an example how a property graph could be defined on top of these tables:

CREATE PROPERTY GRAPH myshop<br>VERTEX TABLES (<br>products,<br>customers,<br>orders<br>EDGE TABLES (<br>order_items SOURCE orders DESTINATION products,<br>customer_orders SOURCE customers DESTINATION orders<br>);

This graph could then be queried like this:

-- get list of customers active today<br>SELECT customer_name FROM GRAPH_TABLE (myshop MATCH (c IS customers)-[IS customer_orders]->(o IS orders WHERE o.ordered_when = current_date) COLUMNS (c.name AS customer_name));

corresponding approximately to this relational query:

-- get list of customers active today<br>SELECT customers.name FROM customers JOIN customer_orders USING (customer_id) JOIN orders USING (order_id) WHERE orders.ordered_when = current_date;

The above definition requires that all tables have primary keys and that for each edge there is an appropriate foreign key. Otherwise, additional clauses have to be specified to identify the key columns. For example, this would be the fully verbose definition that does not rely on primary and foreign keys:

CREATE PROPERTY GRAPH myshop<br>VERTEX TABLES (<br>products KEY (product_no),<br>customers KEY (customer_id),<br>orders KEY (order_id)<br>EDGE TABLES (<br>order_items KEY (order_items_id)<br>SOURCE KEY (order_id) REFERENCES orders (order_id)<br>DESTINATION KEY (product_no) REFERENCES products (product_no),<br>customer_orders KEY (customer_orders_id)<br>SOURCE KEY (customer_id) REFERENCES customers (customer_id)<br>DESTINATION KEY (order_id) REFERENCES orders (order_id)<br>);

As mentioned above, by default, the names of the tables and columns are exposed as labels and properties, respectively. The clauses IS customer, IS order, etc. in the MATCH clause in fact refer to labels, not table names.

One use of labels is...

graph property tables orders customers order_id

Related Articles