Pangram verdict · v3.3
We believe that this text is a mix of AI and human-written content.
AI likelihood · overall
MixedArticle text · 627 words · 4 segments analyzed
PostgreSQL 19 is in beta, with general availability expected around September or October 2026, so it’s a good time to get a head start on what’s new. The official release notes are the authoritative record: meticulously assembled, complete down to the commit and the contributors behind each change.
This article is a hands-on companion to them, taking a selection of those entries and turning each into a runnable example so you can see how the new behavior actually works.Before we start digging into the new features, let’s set the context.This article is based on the official release notes and the PostgreSQL source code, licensed under the PostgreSQL License. This is not an exhaustive list; see the official release notes for that.Every example below was run against PostgreSQL 19 beta 3 (released 2026-08-13) and the output is what that server actually printed.Links point to the documentation (𝗗), the most relevant commits (𝗖), and authors (𝗔) for each feature; check them out for motivation, usage, and implementation details. The authors (𝗔) are the people credited in the release notes for the feature, which usually means the patch authors rather than a single main author.With the context set, let’s start exploring the new features.Property graph queries#This is the headline of the release. PostgreSQL 19 implements SQL/PGQ, the property-graph part of SQL:2023. You declare a property graph over existing tables, then query it with pattern matching instead of writing the joins yourself.Two ordinary tables, one graph on top of them:CREATE PROPERTY GRAPH social VERTEX TABLES ( person KEY (id) LABEL person PROPERTIES (id, name) ) EDGE TABLES ( follows KEY (follower, followee) SOURCE KEY (follower) REFERENCES person (id) DESTINATION KEY (followee) REFERENCES person (id) LABEL follows ); Nothing is copied: social is a view-like object that says “person rows are vertices, follows rows are edges”.
Now you can match patterns with GRAPH_TABLE, where -[...]-> is a directed edge:SELECT * FROM GRAPH_TABLE (social MATCH (a IS person)-[IS follows]->(b IS person) COLUMNS (a.name AS follower, b.name AS followee) ) ORDER BY follower, followee; ┌──────────┬──────────┐ │ follower │ followee │ ├──────────┼──────────┤ │ Ada │ Bo │ │ Ada │ Dee │ │ Bo │ Cleo │ │ Cleo │ Dee │ └──────────┴──────────┘ (4 rows) The payoff is multi-hop patterns. Chaining two edges gives you friends-of-friends without a self-join, and an empty () means “some vertex I don’t care to name”:SELECT * FROM GRAPH_TABLE (social MATCH (a IS person WHERE a.name = 'Ada')-[IS follows]->()-[IS follows]->(c IS person) COLUMNS (a.name AS start, c.name AS friend_of_friend) ); ┌───────┬──────────────────┐ │ start │ friend_of_friend │ ├───────┼──────────────────┤ │ Ada │ Cleo │ └───────┴──────────────────┘ (1 row) There’s no new execution engine here, and that’s the point.
GRAPH_TABLE is rewritten into a plain relational query, so the planner, the statistics, and the index choices you already know all still apply:EXPLAIN (COSTS OFF) SELECT * FROM GRAPH_TABLE (social MATCH (a IS person)-[IS follows]->(b IS person) COLUMNS (a.name AS follower, b.name AS followee) ); ┌───────────────────────────────────────────────────┐ │ QUERY PLAN │ ├───────────────────────────────────────────────────┤ │ Hash Join │ │ Hash Cond: (follows.followee = person_1.id) │ │ -> Hash Join │ │ Hash Cond: (follows.follower = person.id) │ │ -> Seq Scan on follows │ │ -> Hash │ │ -> Seq Scan on person │ │ -> Hash │ │ -> Seq Scan on person person_1 │ └───────────────────────────────────────────────────┘ (9 rows) One limitation to know before you plan a migration off a graph database: this first cut has no variable-length paths. Quantifiers like -[IS follows]->{1,3} parse but are rejected with element pattern quantifier is not supported, so a pattern has to spell out every hop.𝗗 Graph Queries, Property Graphs, CREATE PROPERTY GRAPH𝗖 2f094e7, c5b3253, a0dd070𝗔 Peter Eisentraut, Ashutosh BapatTemporal updates and deletes#The new FOR PORTION OF clause on UPDATE and DELETE operates on a slice of a range column.