PgQue: Zero-Bloat Postgres Queue

PgQue brings the battle-tested PgQ architecture to modern managed Postgres environments using pure PL/pgSQL. It eliminates table bloat through snapshot-based batching and table rotation, making it ideal for high-throughput systems.
Zero-bloat Postgres queue. One SQL file to install, pg_cron to tick.
PgQue brings back PgQ — one of the longest-running Postgres queue architectures in production — in a form that runs on any Postgres platform, managed providers included.
PgQ was designed at Skype to run messaging for hundreds of millions of users, and it ran on large self-managed Postgres deployments for over a decade. Standard PgQ depends on a C extension (pgq) and an external daemon (pgqd), neither of which run on most managed Postgres providers.
PgQue rebuilds that battle-tested engine in pure PL/pgSQL, so the zero-bloat queue pattern works anywhere you can run SQL — without adding another distributed system to your stack.
The anti-extension. Pure SQL + PL/pgSQL on any Postgres 14+ — including RDS, Aurora, Cloud SQL, AlloyDB, Supabase, Neon, and most other managed providers. No C extension, no shared_preload_libraries, no provider approval, no restart.
Most Postgres queues rely on SKIP LOCKED plus DELETE and/or UPDATE. That holds up in toy examples and then turns into dead tuples, VACUUM pressure, index bloat, and performance drift under sustained load.
PgQue avoids that whole class of problems. It uses snapshot-based batching and TRUNCATE-based table rotation instead of per-row deletion. The hot path stays predictable:
- Zero bloat by design— no dead tuples in the main queue path
- No performance decay— it does not get slower because it has been running for months
- Built for heavy-loaded systems— the sustained-load regime the original PgQ architecture was designed for
- Real Postgres guarantees— ACID transactions, transactional enqueue/consume, WAL, backups, replication, SQL visibility
- Works on managed Postgres— no custom build, no C extension, no separate daemon
PgQue gives you queue semantics inside Postgres, with Postgres durability and transactional behavior, without the bloat tax most in-database queues eventually hit.
Latency trade-off
The trade-off is end-to-end delivery latency — the gap between send and when a consumer can receive the event. In the default configuration, end-to-end delivery typically lands within ~1–2 seconds: up to 1 s for the next tick, plus the consumer's poll interval. Per-call latency (the send / receive / ack functions themselves) stays in the microsecond range.
If your top priority is single-digit-millisecond dispatch, PgQue is the wrong tool. If your priority is stability under load without bloat, that is where PgQue fits.
Quick Start
Requirements: Postgres 14+, and something that calls pgque.ticker() periodically (every 1 second by default). pg_cron is the recommended default.
Inside a psql session:
begin;
\i sql/pgque.sql
commit;
With pg_cron available in the same database as PgQue, pgque.start() creates the default ticker and maintenance jobs:
select pgque.start();
Source: Hacker News










