PostgreSQL 19 Interactive Tour
A Hands-On Guide to PostgreSQL 19
PostgreSQL 19 is currently in its beta phase, with the general availability (GA) release anticipated around September or October 2026. Now is the ideal moment to familiarize yourself with the upcoming enhancements.
While the official release notes serve as the definitive, comprehensive record—detailing every single commit and contributor—this article acts as a practical companion. I have selected key updates and transformed them into executable examples to demonstrate how these new behaviors function in a real-world scenario.
📌 Context & Prerequisites
Before we dive in, here is the framework for this tour:
- Source Material: This guide is derived from the PostgreSQL source code and official release notes (licensed under the PostgreSQL License).
- Scope: This is
an exhaustive lista curated selection of features. Please refer to the official notes for the full inventory. - Environment: All examples were executed using PostgreSQL 19 beta 3 (released
2026-08-13). - References: Throughout the text, you will see markers for:
- 𝗗: Documentation
- 𝗖: Relevant Commits
- 𝗔: Credited Authors (typically the patch authors)
Tour Checklist:
- Property Graph Queries
- Temporal Updates and Deletes
- Additional features (to be explored)
🕸️ Property Graph Queries
This is undoubtedly the "crown jewel" of the PostgreSQL 19 release. The engine now implements SQL/PGQ, which is the property-graph component of the SQL:2023 standard.
Essentially, you can now define a property graph on top of your existing relational tables and query it using pattern matching, eliminating the need to manually write complex joins.
Defining the Graph
You can create a graph without duplicating any data. The graph is a virtual layer (similar to a view) that maps tables to vertices and edges.
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
);
Visualizing the Logic
Querying with GRAPH_TABLE
Using the GRAPH_TABLE function, you can use the -[...]-> syntax to represent directed edges.
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;
Output:
| follower | followee |
|---|---|
| Ada | Bo |
| Ada | Dee |
| Bo | Cleo |
| Cleo | Dee |
| (4 rows) |
The Power of Multi-Hop Patterns
The real advantage appears when querying "friends-of-friends." By chaining edges, you avoid self-joins. An empty parenthesis () represents an anonymous vertex.
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 )
);
Output:
| start | friend_of_friend |
|---|---|
| Ada | Cleo |
| (1 row) |
Under the Hood
There is no separate graph engine. GRAPH_TABLE is rewritten into a standard relational query, meaning the existing optimizer, statistics, and indexes are still utilized.
Execution Plan Example:
EXPLAIN ( COSTS OFF ) SELECT * FROM GRAPH_TABLE ( social MATCH ( a IS person ) - [ IS follows ] - ( b IS person ) COLUMNS ( a.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 │ └───────────────────────────────────────────────────┘
⚠️ Important Limitation:
This initial implementation does not support variable-length paths. While quantifiers like -[IS follows]->{1,3} will parse, they will be rejected with the error: element pattern quantifier is not supported. Every hop must be explicitly defined.
References: 𝗗 Graph Queries, Property Graphs, CREATE PROPERTY GRAPH | 𝗖 2f094e7, c5b3253, a0dd070 | 𝗔 Peter Eisentraut, Ashutosh Bapat.
⏳ Temporal Updates and Deletes
PostgreSQL 19 introduces the FOR PORTION OF clause for UPDATE and DELETE statements. This allows you to modify a specific slice of a range column without rewriting the entire record.
How it Works
Instead of manually calculating how to split a validity period, you specify the sub-period, and PostgreSQL handles the row splitting automatically.
Initial State: Imagine a table where a product price is valid for the entire year of 2026.
SELECT * FROM price ORDER BY valid_at;
| sku | valid_at | amount |
|---|---|---|
| widget | [2026-01-01, 2027-01-01) | 9.99 |
The Update: We want to change the price to $7.99 for the month of July only.
UPDATE price
FOR PORTION OF valid_at FROM '2026-07-01' TO '2026-08-01'
SET amount = 7.99;
Resulting State: One row has now become three. The periods outside of July retain the original price.
SELECT * FROM price ORDER BY valid_at;
| sku | valid_at | amount |
|---|---|---|
| widget | [2026-01-01, 2026-07-01) | 9.99 |
| widget | [2026-07-01, 2026-08-01) | 7.99 |
| widget | [2026-08-01, 2027-01-01) | 9.99 |
This concludes the current segment of the PostgreSQL 19 tour. Stay tuned for more updates as the beta progresses toward the final release.