Starting with version 19 of PostgreSQL users will be able to enjoy something exceptionally useful which will help developers to build even more powerful applications even more quickly. SQL/PGQ — the ISO/IEC 9075-16 (2023) syntax for querying graphs that live in regular relational tables - will be available. This series of posts will explain how this new functionality works and how it can be used to leverage the power of PostgreSQL 19 and beyond.
The addition introduces two SQL constructs: Namely CREATE PROPERTY GRAPHand GRAPH_TABLE. Let us take a look at the definition of the property graph:
friends=# \h CREATE PROPERTY GRAPH
Command: CREATE PROPERTY GRAPH
Description: define a new SQL-property graph
Syntax:
CREATE [ TEMP | TEMPORARY ] PROPERTY GRAPH name
[ {VERTEX|NODE} TABLES ( vertex_table_definition [, ...] ) ]
[ {EDGE|RELATIONSHIP} TABLES ( edge_table_definition [, ...] ) ]
where vertex_table_definition is:
vertex_table_name [ AS alias ]
[ KEY ( column_name [, ...] ) ]
[ element_table_label_and_properties ]
and edge_table_definition is:
edge_table_name [ AS alias ] [ KEY ( column_name [, ...] ) ]
SOURCE [ KEY ( column_name [, ...] )
REFERENCES ] source_table [ ( column_name [, ...] ) ]
DESTINATION [ KEY ( column_name [, ...] )
REFERENCES ] dest_table [ ( column_name [, ...] ) ]
[ element_table_label_and_properties ]
and element_table_label_and_properties is either:
NO PROPERTIES | PROPERTIES ALL COLUMNS | PROPERTIES
( { expression [ AS property_name ] } [, ...] )
or:
{ { LABEL label_name | DEFAULT LABEL }
[ NO PROPERTIES | PROPERTIES ALL COLUMNS | PROPERTIES
( { expression [ AS property_name ] } [, ...] ) ] } [...]
URL: https://www.postgresql.org/docs/devel/sql-create-property-graph.html
Before we dig into this in more detail we need to understand what the purpose of all of this is: In a relational database things are stored as tables. What CREATE PROPERTY GRAPH does is to defi
[...]
Part one made the core case: pg_stat_statements counts, it doesn't record. It walked through how the queryid jumble fragments one logical query into many rows, how the first-seen text freezes your per-request tags, and how the averages bury the p99 that actually pages you. All of that was about data the extension has and distorts.
This part is about the rest: the entries it silently throws away, the query text that can vanish all at once, the plans and replicas it never records, and the knobs that bite. It ends where part one started, with the question the whole investigation was really about: is this the query store Postgres is missing, or just the floor you'd build one on?
pg_stat_statements.max defaults to 5000. It's a hard cap on entries, set when the server starts (changing it needs a restart, because the hash table is sized in shared memory up front). When the 5001st distinct shape arrives, Postgres doesn't grow the table. It evicts, throwing out the least-executed entries to make room:
If more distinct statements than that are observed, information about the least-executed statements is discarded.
On a healthy app with a few hundred steady shapes, 5000 is plenty and you never think about it. But remember the row explosion from part one. An ORM that splinters one query into hundreds of shapes, or a pre-18 app building dynamic IN lists, can chew through thousands of entries an hour. Once that starts, the view becomes a sliding window over recent noise. Your steady, important queries get evicted to make room for thousands of one-offs, then rebuilt with fresh counters and a fresh first-seen text when they run again. The stats you were trusting reset themselves, and the view never says a word about it.
One place does say something. The companion view pg_stat_statements_info has exactly two columns, and both matter:
SELECT dealloc, stats_reset FROM pg_stat_statements_info;
dealloc | stats_reset
---------+-----------------------[...]
If not first, pg_stat_statements is one of the most used extensions in the PostgreSQL ecosystem. It ships in contrib and costs almost nothing to use. Most of us turn to it to answer the question: what is the database actually doing? It's genuinely useful. You can use it to get a snapshot of what happened in a given timeframe, and make a faster decision about what to fix.
Coming from other database engines, you might reach for it expecting something a bit more, a query store. The built-in feature that keeps normalized queries and their plan history. Except pg_stat_statements is not this. This article is going to deep dive into what the extension really provides.
Because once you lean on it, you might start noticing the rough edges. The gap comes from what "a query store" might come with and what it actually tells you.
The very same query might show up in many separate rows. Discrepancies between what your monitoring says and what mean_exec_time shows. Missing queries. Numbers that changed overnight.
None of that is a bug. It all follows from what pg_stat_statements really is: a fixed-size hash table of running counters, kept in shared memory, keyed by a hash of your parse tree. It counts; it does not record. Hold that one idea in your head and every surprising thing on the list above stops being surprising.
Everything below is reproducible. Paste this into a scratch database:
CREATE TABLE customers (
id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name text NOT NULL
);
CREATE TABLE orders (
id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
customer_id integer NOT NULL REFERENCES customers(id),
amount numeric(10,2) NOT NULL,
status text NOT NULL DEFAULT 'pending',
created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO customers (name)
SELECT 'Customer ' || i FROM generate_series(1, 2000) AS i;
INSERT INTO orders (customer_id, amount, status, created_at)
SELECT (random() * 1999 + 1)::int,
(random() * 500 + 5)::numeric(10,2),
[...]

© Laurenz Albe 2026
Instigated by a customer, I've been trying to improve the performance of row-level security. Central to good performance in this area is the concept of leakproof functions and operators. I'll go over the priciples quickly, but I'll focus on the question what leakproof really means, and what it should mean. In a way, this article is a request for comments: I'd be curious what you think about the topic!
PostgreSQL has two related features to hide table rows from a user: Security barrier views and row-level security. The usual reason why you want to hide parts of a table is multi-tenancy: you want to store data belonging to different entities (tenants) in a single table, and you want to prevent any tenant from seeing or manipulating the other tenants' data. You can certainly implement such restrictions in the application code. However, having a ready-made reliable solution inside the database is a good thing.
This is the older of the two techniques, introduced in PostgreSQL 9.2. It makes use of how PostgreSQL checks the privileges on the objects used by a view: as long as the owner of the view has the permission to access the objects, anybody with privileges on the view can use it. That makes definitions like the following feasible:
CREATE TABLE account ( account_nr bigint PRIMARY KEY, owner text NOT NULL, amount numeric(15,2) NOT NULL ); CREATE INDEX account_owner_idx ON account (owner); CREATE VIEW my_account AS SELECT account_nr, owner, amount FROM account WHERE owner = current_user; GRANT SELECT, INSERT ON my_account TO PUBLIC;
Using the view, every database role can look at their own account, even though they don't have any privileges on the account table.
Note that I also granted everybody the INSERT privilege on the view. It may surprise some people, but you can also use data modifying statements on views (provided that the view definition is
On May 26 2026, the Bratislava PostgreSQL Meetup came together, organized by Pavlo Golub and Meego Smith. Mayur B. and Devrim Gündüz delivered a presentation.
About 90 attendees showed up for the NYC Postgres meetup that took place May 27 with Gleb Otochkin speaking.
Organizers:
On Thursday, 28 May, the PostgreSQL User Group Vienna met for a casual networking event, organized by Cornelia Biacsics.
On Friday, 29 May 2026 the Ghana PostgreSQL Users Group met for the first virtual meetup, organized by Benedict Kofi Amofah and Ezra Yendau
Community Blog Posts
The shared presentations are online, as are a couple of recordings and turtle-loading have-a-cup-of-tea locally stored photos.
Using the well known and broadly spread technique of inductive reasoning we came to the conclusion that this fifth PGConf.be conference was a success, as well as the art work. No animals or elephants we’re hurt during this event.
The statistics are
75 attendants
depending on the session, an extra 200 students attended as well
14 speakers
4 sponsors
This conference wouldn’t have been possible without the help of volunteers.
To conclude a big thank you to all the speakers, sponsors and attendants.
Without them a conference is just a like tee party.
Postgres has had a thorn in its paw for a very long time regarding table size. Every modified tuple leaves an old version in the heap for use by older transactions. While locates these old tuples, it only marks them as reusable rather than returning the space to the OS. Tables only ever grow larger in Postgres.Maybe Postgres 19 can fix that for us.
Last week, we attended the annual PGConf.dev as a Gold-level sponsor. While most PostgreSQL conferences usually attract users and DBAs, this event draws a strong mix of contributors and community members alike, making it a unique opportunity to get proposals and patches reviewed and to connect across the broader Postgres ecosystem.
Our team played a major role behind the scenes. Robert Haas helped organize the event, tackling the impressive feat of shaping Tuesday's content across six tracks. Additionally, Jacob Champion served on the Talk Selection Committee, and Phil Alger, Manni Wood
Thanks to the organising team, I had the chance to attend PGConf.dev last week in Vancouver, Canada. And luckily, I wasn’t alone there — Valeria could join as well!
This year’s edition was particularly special: we celebrated 30 years of open source PostgreSQL together! Many activities revolved around the anniversary, including a special celebration-themed conference t-shirt, stickers, commemorative posters, and more.
My personal highlight was definitely Wednesday’s round-table retrospective, which brought together project founders and early contributors to reflect on PostgreSQL’s formative years and its remarkable evolution. Featuring Bruce Momjian, Tom Lane, Thomas Lockhart, Jan Wieck, Vadim Mikheev, and Jolly Chen, the discussion revisited what the Postgres project was like in its earliest open source incarnation — technically, culturally, and socially.
Then, on Thursday, a birthday cake cutting ceremony took place following a short speech from Bruce Momjian.
Even though the project still relies on decisions made in its early days — such as hacker mailing-list-focused discussions and documentation written close to the source code using DocBook — it is hard to imagine where PostgreSQL will be 10 or 20 years from now.
Especially today, with AI-assisted content generation accelerating code writing (though not necessarily code review!), the project will inevitably evolve. But as Jan Wieck concluded during the panel, we should take care to preserve and foster the PostgreSQL spirit.
After the panel, a group photo was organised. I can’t wait to see the result!
Speaking of pictures, a photo booth was set up to let attendees take funny pictures celebrating PostgreSQL’s 30th anniversary. As member of the PGDay Lowlands 2026 talk selection committee, I couldn’t resist taking a picture together with Floor Drees, who was the only representative from the organising team attending the event.
This year’s PGConf.dev schedule was divided into three parts.
Tuesda
[...]A field report from PGConf Dev 2026 — and a working framework for everyone who has to keep AI workloads running in production.
A production AI batch job is stuck. Sixty thousand rows are locked. Your application performance is degrading. The post-mortem the next morning will be filed under “unknown cause.”
Here is what actually happened, minute by minute:
The root cause has a name, but it’s a name the industry hasn’t agreed on yet: external call state held inside an open transaction. There is no alert for it. There is no entry in the runbook. There is no metric you can graph. The post-mortem says “unknown cause” because we don’t yet have a shared vocabulary for this failure mode.
I gave a talk at PGConf Dev about this and a class of related production incidents. By the end of the session, I wanted the audience to walk away with two things: enough technical understanding to fix something on Monday morning, and enough conceptual vocabulary to argue for the right primitives in the Postgres community.
This post is the long-form version of that talk. It introduces a five-letter framework — ORBIT — that maps every failure mode I’ll discuss to one of five principles, and shows how the same framework applies whether you’re an SRE staring at a pager, an Enterp
[...]This series is aimed at recounting, explaining, and cataloging issues pertaining to Postgres in large-scale production environments that affected a wide section of users and clients. The idea occured to me when discussing one specific issue (covered in a later part in this series) that was my first experience dealing with such issues on a wide scale (multiple clients and clusters affected). This specific part focuses on issues that were caused not by Postgres itself, but by the tools, OS, and ecosystems that Postgres relies on.
Three of the worst Postgres incidents I have read postmortems for did not start in Postgres. They started one layer down: the kernel, glibc, the page allocator. Postgres handled the input correctly given what it was told.
I want to cover these first because the fixes are cheap and most teams still ship without them.
For years, Postgres assumed that if fsync() returned success, the data was on disk, and if it returned an error, it could be retried. Linux did neither. Under writeback errors on some filesystems, the kernel cleared the error after the first reader saw it. The next fsync() returned success while pages were still dirty in memory and never made it to disk.
This came to be known as fsyncgate. The fix in Postgres was to PANIC on fsync() failure (PG 11+), forcing recovery from WAL instead of trusting the OS to retry. There is also data_sync_retry, which you almost certainly want set to off.
What this means for an operator:
fsync semantics. Many do not, and the docs rarely say so plainly.
For the long version of how this came to light on the pgsql-hackers list, Jonathan Corbet's PostgreSQL's fsync() surprise on LWN is the canonical writeup.
The Iceberg tables look like normal Postgres tables. You create them with USING iceberg and they're backed by Parquet on S3:
Postgres engines now have access to more data than ever. With extensions like pg_lake, you can connect Postgres to gobs of files in object storage like csv, json, Apache Parquet™ and Apache Iceberg™.
But having access to data in object storage and being able to aggregate data in object storage are two different things. This blog walks through the Postgres extension, Apache AGE™, that makes working with huge files of data sets much friendlier through graph relationships.
Let's consider a healthcare network with providers, patients, facilities and referral chains. The analytical questions are straightforward:
SQL on Iceberg handles all of these beautifully. But if you need to know: "Which in-network providers are referring patients to out-of-network providers through chains of intermediaries, and what's the dollar impact?" Those questions have two parts: a graph traversal (find the referral chains) and an analytical aggregation (sum the costs). Neither a pure graph database nor a pure analytical engine can answer it alone. You need both, working together, in the same query.
This is where data lakes need graphs.
Apache AGE is a PostgreSQL extension that adds openCypher graph query support directly inside Postgres. There are other graph databases out there — Neo4j, Amazon Neptune, TigerGraph — but AGE has a unique advantage for the modern data platform — it runs inside PostgreSQL.
We've recently seen customers increasingly using Apache AGE for a couple of reasons:
PGConf.dev is an annual developer event focused entirely on contributing to the PostgreSQL ecosystem, including core software development and community building. It serves as a primary hub for PostgreSQL hackers, maintainers, and ecosystem developers to meet, collaborate, and share knowledge.
This year’s conference was hosted once again in Vancouver, which also happens to be my hometown :D. On top of that, 2026 also marks PostgreSQL’s 30th anniversary, giving this year’s conference an even more meaningful atmosphere for long-time contributors and community members around the world.
This is one of my favorite PostgreSQL conferences because it gives people an opportunity to truly meet, learn from, and interact with the brilliant minds behind PostgreSQL. Many of the names we usually only see in hacker mailing list discussions, patch reviews and commit messages suddenly become real people standing right beside you, discussing ideas and working together to make PostgreSQL better.
It feels like the PostgreSQL hacker discussions have come to life in the real world. The conversations are real, the passion is real, and the community spirit is everywhere.
A huge thank you once again to all the organizers, volunteers, speakers, and sponsors who invested countless hours to make this conference possible. This blog is a personal summary of my own experience attending pgconf.dev 2026, and for those who could not attend, I hope it can give you at least a small glimpse of what it feels like to be part of this incredible PostgreSQL community.
Unlike the “Tuesdays” from previous pgconf.dev conferences, this year’s Tuesday schedule is packed with an impressive variety of engaging sessions, including round-table discussions, interviews, keynote-style talks, brainstorming sessions, and community-led discussions focused on spe
[...]Number of posts in the past two months
Number of posts in the past two months
Get in touch with the Planet PostgreSQL administrators at planet at postgresql.org.