<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/postgresql-queues-done-right-with-pgq-posette-an-event-for-postgres-2026-wza8y552h" -->

---
title: PostgreSQL queues done right with PgQ | POSETTE: An...
description: PgQ is a PostgreSQL extension for implementing queues that has existed since 2007, and this talk explains why it outperforms the common SELECT FOR UPDATE SKIP...
canonical: https://daily.dev/posts/postgresql-queues-done-right-with-pgq-posette-an-event-for-postgres-2026-wza8y552h
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: PostgreSQL queues done right with PgQ | POSETTE: An Event for Postgres 2026 | daily.dev
og:description: PgQ is a PostgreSQL extension for implementing queues that has existed since 2007, and this talk explains why it outperforms the common SELECT FOR UPDATE SKIP...
og:url: https://daily.dev/posts/postgresql-queues-done-right-with-pgq-posette-an-event-for-postgres-2026-wza8y552h
og:image: https://api.daily.dev/og/posts/WZa8Y552h.png
og:image:alt: PostgreSQL queues done right with PgQ | POSETTE: An Event for Postgres 2026
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# PostgreSQL queues done right with PgQ | POSETTE: An Event for Postgres 2026

**[Microsoft Developer](https://daily.dev/sources/microsoftdeveloper)** · 28 min read · 0 upvotes · 0 comments

## Summary

PgQ is a PostgreSQL extension for implementing queues that has existed since 2007, and this talk explains why it outperforms the common SELECT FOR UPDATE SKIP LOCKED approach. The SKIP LOCKED pattern causes table bloat, dead tuples, excessive UPDATEs/DELETEs, and planner confusion. PgQ solves these problems using snapshot-based event handling, table inheritance with rotating child tables, batch processing, and a maintenance daemon (pgqd). The extension produces zero dead tuples and no write overhead on queue tables. For managed cloud Postgres services that don't natively support PgQ, it can be compiled as pure PL/pgSQL using 'make plonly', and pgqd's functionality can be replicated using pg_cron with custom wrapper procedures. The talk covers the full SQL API, internal architecture, and practical deployment strategies.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.youtube.com/watch?v=N5b0CayG5rg>

## Questions this post answers

### Why does SELECT FOR UPDATE SKIP LOCKED cause table bloat when used for a queue in Postgres?

Because processing events with SKIP LOCKED requires updating and deleting rows repeatedly (the select-for-update, the visibility timeout update, and the final delete each touch the row), producing dead tuples that require aggressive vacuuming. Under a spike of inserts and slow consumers, the queue table grows faster than autovacuum can clean it, and adding a visibility timeout index disables HOT updates and can confuse the query planner into slow index choices.

_Anyone weighing queue designs against bloat risk can track deep dives like this on daily.dev._

### How does the PgQ Postgres extension avoid table bloat compared to a homemade queue table?

PgQ uses table inheritance with a rotating set of child event tables per queue, switching to a new child table roughly every 2 hours and truncating old ones once fully processed, so autovacuum is disabled on these tables since no updates or deletes ever occur on them. Batches are defined by ticks and MVCC snapshot visibility rather than row locking, eliminating dead tuples and update overhead entirely.

_Developers evaluating Postgres extensions for production queues can follow this kind of architecture breakdown on daily.dev._

### How can I run the PgQ Postgres extension on a managed cloud database that doesn't support it natively?

Build PgQ using the 'make plonly' target, which compiles it using only PL/pgSQL functions instead of the four C functions normally used for performance, producing a plain SQL file you can execute directly in your database just like CREATE EXTENSION. For the required pgqd maintenance daemon, run it on a small external VM or reimplement its three tasks (ticking, retries, maintenance) as pg_cron jobs, since pg_cron is supported by most managed Postgres providers.

_Teams stuck without extension support on managed Postgres can find workaround guides like this on daily.dev._

## Similar posts on daily.dev

- [GitHub - NikolayS/pgque: PgQue – Zero-bloat Postgres queue. One SQL file to install, pg\_cron to tick.](https://daily.dev/posts/github---nikolays-pgque-pgque-zero-bloat-postgres-queue-one-sql-file-to-install-pg-cron-to-tick-idiaxcm6k) · Hacker News · 80 upvotes · 3 comments
- [PgQ and PgQue: Workflow Engines you might need in PostgreSQL](https://daily.dev/posts/pgq-and-pgque-workflow-engines-you-might-need-in-postgresql-cglyhhqde) · Planet PostgreSQL · 1 upvotes · 0 comments
- [Potential Consequences of Using Postgres as a Job Queue](https://daily.dev/posts/potential-consequences-of-using-postgres-as-a-job-queue-kcv0c9q1v) · Lobsters · 70 upvotes · 0 comments

---

Tags: [#architecture](https://daily.dev/tags/architecture), [#postgresql](https://daily.dev/tags/postgresql)

[View this post on daily.dev](https://daily.dev/posts/postgresql-queues-done-right-with-pgq-posette-an-event-for-postgres-2026-wza8y552h)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"PostgreSQL queues done right with PgQ | POSETTE: An Event for Postgres 2026","url":"https://daily.dev/posts/postgresql-queues-done-right-with-pgq-posette-an-event-for-postgres-2026-wza8y552h","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/postgresql-queues-done-right-with-pgq-posette-an-event-for-postgres-2026-wza8y552h"},"datePublished":"2026-06-17T12:11:42.140Z","dateModified":"2026-09-13T21:26:50.946Z","description":"PgQ is a PostgreSQL extension for implementing queues that has existed since 2007, and this talk explains why it outperforms the common SELECT FOR UPDATE SKIP...","image":"https://i.ytimg.com/vi/N5b0CayG5rg/sddefault.jpg","thumbnailUrl":"https://i.ytimg.com/vi/N5b0CayG5rg/sddefault.jpg","isAccessibleForFree":true,"articleSection":"Microsoft Developer","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Microsoft Developer","logo":"https://media.daily.dev/image/upload/s--xZzU3zUq--/f_auto/v1746714872/logos/microsoftdeveloper","url":"https://daily.dev/sources/microsoftdeveloper"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/postgresql-queues-done-right-with-pgq-posette-an-event-for-postgres-2026-wza8y552h","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"architecture,postgresql","timeRequired":"PT28M","video":{"@type":"VideoObject","name":"PostgreSQL queues done right with PgQ | POSETTE: An Event for Postgres 2026","description":"PgQ is a PostgreSQL extension for implementing queues that has existed since 2007, and this talk explains why it outperforms the common SELECT FOR UPDATE SKIP...","thumbnailUrl":"https://i.ytimg.com/vi/N5b0CayG5rg/sddefault.jpg","uploadDate":"2026-06-17T12:11:42.140Z","duration":"PT28M","url":"https://api.daily.dev/r/WZa8Y552h","embedUrl":"https://www.youtube.com/embed/N5b0CayG5rg"}}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Microsoft Developer","item":"https://daily.dev/sources/microsoftdeveloper"},{"@type":"ListItem","position":3,"name":"PostgreSQL queues done right with PgQ | POSETTE: An Event for Postgres 2026"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/postgresql-queues-done-right-with-pgq-posette-an-event-for-postgres-2026-wza8y552h#faq","mainEntity":[{"@type":"Question","name":"Why does SELECT FOR UPDATE SKIP LOCKED cause table bloat when used for a queue in Postgres?","acceptedAnswer":{"@type":"Answer","text":"Because processing events with SKIP LOCKED requires updating and deleting rows repeatedly (the select-for-update, the visibility timeout update, and the final delete each touch the row), producing dead tuples that require aggressive vacuuming. Under a spike of inserts and slow consumers, the queue table grows faster than autovacuum can clean it, and adding a visibility timeout index disables HOT updates and can confuse the query planner into slow index choices. Anyone weighing queue designs against bloat risk can track deep dives like this on daily.dev."}},{"@type":"Question","name":"How does the PgQ Postgres extension avoid table bloat compared to a homemade queue table?","acceptedAnswer":{"@type":"Answer","text":"PgQ uses table inheritance with a rotating set of child event tables per queue, switching to a new child table roughly every 2 hours and truncating old ones once fully processed, so autovacuum is disabled on these tables since no updates or deletes ever occur on them. Batches are defined by ticks and MVCC snapshot visibility rather than row locking, eliminating dead tuples and update overhead entirely. Developers evaluating Postgres extensions for production queues can follow this kind of architecture breakdown on daily.dev."}},{"@type":"Question","name":"How can I run the PgQ Postgres extension on a managed cloud database that doesn't support it natively?","acceptedAnswer":{"@type":"Answer","text":"Build PgQ using the 'make plonly' target, which compiles it using only PL/pgSQL functions instead of the four C functions normally used for performance, producing a plain SQL file you can execute directly in your database just like CREATE EXTENSION. For the required pgqd maintenance daemon, run it on a small external VM or reimplement its three tasks (ticking, retries, maintenance) as pg_cron jobs, since pg_cron is supported by most managed Postgres providers. Teams stuck without extension support on managed Postgres can find workaround guides like this on daily.dev."}}]}
```

