Open-source project
NikolayS/PgQue avatar
NikolayS/PgQue

PgQue for a Durable Postgres Queue Without Row-Level Queue Bloat

PgQue – Zero-bloat Postgres queue built on top of on battle-proven Skype's PgQ. One SQL file to install, pg_cron to tick https://pgque.dev

1,846 stars43 forksPLpgSQLApache-2.0

At a glance

What is it?
PgQue is a PostgreSQL 14+ queue implemented in SQL and PL/pgSQL for durable event streams with independent consumer cursors. Snapshot batching and table rotation avoid the row-deletion bloat associated with SKIP LOCKED queues, at the cost of tick-based delivery latency.
Who is it for?
Adopt PgQue when the queue must stay inside PostgreSQL and durable event delivery matters more than immediate dispatch. Do not choose it for single-digit-millisecond visibility.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 9 days ago.
What is it written in?
Mainly PLpgSQL, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • NikolayS/PgQue1,846 ★ · +5
Star history
Repository2026-10-162026-10-23
NikolayS/PgQue1.8k1.8k

5 Stars in the last 7 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Why PgQue Exists for PostgreSQL Event Streams

PgQue addresses a specific queue design problem: PostgreSQL queues based on SKIP LOCKED, DELETE, or UPDATE can accumulate dead tuples, index bloat, VACUUM pressure, and performance degradation under sustained load. The README positions PgQue as a durable event stream rather than a direct ActiveMQ or RabbitMQ replacement. Its central use case is a shared log read by multiple consumers, with each consumer maintaining an independent cursor. That distinction matters for applications that publish events once and allow separate processing workflows to advance independently.

The intended audience is a team that already uses PostgreSQL and does not want a separate distributed messaging system. PgQue is written in SQL and PL/pgSQL and supports PostgreSQL 14 and later. The README names managed services such as RDS, Aurora, Cloud SQL, AlloyDB, Supabase, and Neon as deployment examples. PgQue does not require a C extension, `shared_preload_libraries`, a provider-specific extension approval, a restart, or a sidecar daemon.

This is narrower than a general-purpose messaging broker. It emphasizes transactional enqueue and consume operations, PostgreSQL durability, ACID transactions, WAL, backups, replication, and SQL visibility. A team that needs immediate dispatch or operates as a separate service from its database should examine the scheduler dependency and latency model before committing to it.

Snapshot Batching and Table Rotation Inside PostgreSQL

PgQue does not claim queued rows one at a time through the row-deletion pattern described in the README. It uses snapshot-based batching and TRUNCATE-based table rotation. Consumers receive pre-built batches, while TRUNCATE removes an entire generation of queue data rather than leaving behind a sequence of individually deleted rows. According to the README, this keeps the main queue path free of dead tuples and avoids the bloat pattern that it associates with SKIP LOCKED queues.

The visibility model comes from consecutive tick snapshots. The repository links an external explanation that describes two snapshots and a diff as the mechanism for determining which events become visible to consumers. This means event visibility is tied to queue processing cycles rather than solely to the instant a worker happens to poll. A newly sent event becomes visible after it is included in a subsequent batch.

Consumers maintain independent cursors over a shared event log. One consumer can advance without deleting events that another consumer has not processed. This is useful for fan-out processing and durable event history, but it differs from a conventional temporary task-message model. Applications must model consumer progress explicitly rather than assuming that acknowledgement removes an event for every other reader.

The README connects the design to the PgQ architecture created at Skype in 2006. Standard PgQ used a C extension named `pgq` and an external daemon named `pgqd`, which the README says are unavailable on most managed PostgreSQL providers. PgQue reconstructs that architecture in PL/pgSQL and adds client libraries for TypeScript, Python, and Go.

PgQue Tick Period and Delivery Latency

PgQue introduces a scheduling delay between committing an event and making it visible to a consumer. The default tick period is 100 milliseconds, producing 10 ticks per second. The README says the average wait for the next tick is about half of that period. It cites a committed benchmark under `benchmark/tick-rate/` with median end-to-end delivery around 52 milliseconds and a documented maximum of roughly one tick period, about 105 to 145 milliseconds across committed runs, before including the consumer's poll interval.

The README separates queue latency into producer, subscriber, and end-to-end delivery. The `send` or `insert_event` operation handles producer latency. `next_batch` reads a pre-built batch for subscriber latency. End-to-end latency spans both sides and also includes the scheduler tick. Because consumer polling remains part of that path, changing the tick period does not remove the application's own polling delay.

The documented tuning function is `pgque.set_tick_period_ms(50)`. The README says passing 50 milliseconds creates 20 ticks per second. Accepted periods must be exact divisors of 1000 milliseconds. PgQue also documents `force_next_tick()` for tests, demonstrations, and forced immediate batches.

PgQue is not appropriate when single-digit-millisecond dispatch is the primary requirement. The README proposes logical-decoding-based wake-ups as a possible future mechanism for sub-millisecond delivery, but it does not present that as a current feature. This boundary is central to evaluating the project against RabbitMQ, Kafka, or another transport optimized specifically for dispatch latency.

Installing PgQue and Performing the First Tick Adjustment

The repository description says that PgQue uses one SQL file for installation and can be ticked with `pg_cron` or `pg_timetable`. The README lists Installation, Roles and grants, and Quick start as separate documentation sections. It does not give the exact SQL file path, complete installation statements, grant commands, scheduler configuration, or first-use client example. This article does not invent those details.

The first concrete configuration operation named in the README is `pgque.set_tick_period_ms(50)`. A PostgreSQL session that can execute the PgQue function would call that function with 50 to request a 50 millisecond tick period. The README states that the accepted periods are exact divisors of 1000 milliseconds. No SQL wrapper syntax is shown in the README text, so none is included here as an exact project example.

For a first deployment, follow the repository's Installation section to apply its single SQL file, then use its Roles and grants section to confirm which database role needs access. Tick scheduling must come from `pg_cron` or `pg_timetable`. The README does not state which scheduler is required or whether either is preconfigured, so an operator must inspect the project's installation documentation and the target PostgreSQL service rather than assume one.

PgQue on Managed PostgreSQL and Its Scheduler Dependency

PgQue is designed for environments where a C extension or external queue daemon cannot be installed. Its pure SQL and PL/pgSQL implementation is intended to run anywhere the target platform permits the required SQL functions and schedules. The README lists RDS, Aurora, Cloud SQL, AlloyDB, Supabase, and Neon as examples of managed providers, but it does not claim compatibility with every service tier or extension configuration.

The absence of a sidecar does not mean the absence of operational dependencies. A tick scheduler must invoke PgQue's queue-processing cycle. The project identifies `pg_cron` and `pg_timetable` as scheduler options. A managed database that cannot run either extension, or whose role cannot schedule the necessary call, may require a different deployment method or a different queue.

Database capacity also remains relevant because queue operations execute inside PostgreSQL. PgQue inherits the database's transaction, storage, connection, and replication behavior. The README does not publish capacity limits or define how PgQue behaves when the database is saturated, so those areas are not established by the project documentation. Before adoption, confirm that the application can keep its scheduled ticks and consumer polling within the database's operational budget.

PgQue Compared with SKIP LOCKED and Dedicated Brokers

A conventional PostgreSQL task queue often inserts a job, claims it with SKIP LOCKED, and then deletes or updates the claimed row. This can work well for work that leaves little durable history, but repeated row deletion or updates generate dead tuples and index maintenance work. PgQue deliberately chooses snapshot batches and TRUNCATE-based rotation. Its goal is stable queue behavior over long periods of sustained use without accumulating dead rows in the main queue path.

PgQue's shared log and independent consumer cursors are closer to Kafka than to the temporary task messages commonly associated with ActiveMQ or RabbitMQ. This is an advantage when each consumer needs its own progress and events must remain available to multiple readers. It also creates a different application model. A one-time background task may not need replayable history or multiple independent positions.

A dedicated broker separates queue availability and scaling from the PostgreSQL server. PgQue instead keeps queue state, queue functions, and transaction boundaries in the same database. The choice depends on deployment boundaries as much as throughput. PgQue fits an existing PostgreSQL architecture when tick-based latency is acceptable. A dedicated broker is the clearer choice when immediate dispatch or messaging availability independent of PostgreSQL is the main requirement.

PgQue Releases, License, and Upgrade Boundaries

PgQue is distributed under Apache-2.0. The repository contains `LICENSE` and `NOTICE` files. That is the project's declared license, while deployment and redistribution decisions still require reviewing those files and obtaining appropriate legal guidance when necessary.

The repository is not archived, and its last push was on 2026-10-14. Listed releases include v0.2.2 on 2026-10-04, v0.2.1 on 2026-10-01, and v0.3.0-alpha.1 on 2026-07-09. The alpha designation matters when evaluating API stability. It is reasonable to verify whether TypeScript, Python, or Go clients align with the server-side SQL functions before standardizing those interfaces.

The README does not document upgrade commands, migration procedures, rollback steps, or a compatibility matrix. It also does not identify the exact installation file path. The repository layout contains `sql/`, `docs/`, `clients/`, `cli/`, and `tests/`, but those directory names alone do not establish the upgrade process. Operators should inspect `sql/` and the repository documentation for the release being installed rather than infer migration steps from the one-file installation claim.

Editorial conclusion

Adopt PgQue when the queue must stay inside PostgreSQL and durable event delivery matters more than immediate dispatch. Do not choose it for single-digit-millisecond visibility. Verify the PostgreSQL version, scheduler availability, required grants, configured tick period, and release compatibility first.

Frequently asked questions

What problem does PgQue solve?

PgQue provides a durable PostgreSQL event queue without the per-row delete or update pattern associated with SKIP LOCKED queue bloat. It is intended for teams that want queue semantics inside PostgreSQL, including managed databases.

Does PgQue require a PostgreSQL C extension or sidecar daemon?

No. PgQue is implemented in SQL and PL/pgSQL, and the README says it requires neither a C extension nor an external sidecar daemon. It does require PostgreSQL 14 or later and a ticking mechanism such as `pg_cron` or `pg_timetable`.

How does PgQue control delivery latency?

PgQue ticks every 100 milliseconds by default. The README documents `pgque.set_tick_period_ms(50)` for a 50 millisecond period, and says accepted periods must be exact divisors of 1000 milliseconds. PgQue does not present this as a sub-millisecond delivery mechanism.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. NikolayS/PgQue on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/nikolays-pgque.svg)](https://hysenlabs.com/projects/nikolays-pgque)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/nikolays-pgque.svg)](https://hysenlabs.com/projects/nikolays-pgque)

Was this useful?