<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/postgres-listen-notify-actually-scales-wehhixojn" -->

---
title: Postgres LISTEN/NOTIFY actually scales | daily.dev
description: Postgres LISTEN/NOTIFY has a reputation for poor scalability due to a global exclusive lock taken during NOTIFY commits. This lock serializes all transactions...
canonical: https://daily.dev/posts/postgres-listen-notify-actually-scales-wehhixojn
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Postgres LISTEN/NOTIFY actually scales | daily.dev
og:description: Postgres LISTEN/NOTIFY has a reputation for poor scalability due to a global exclusive lock taken during NOTIFY commits. This lock serializes all transactions...
og:url: https://daily.dev/posts/postgres-listen-notify-actually-scales-wehhixojn
og:image: https://api.daily.dev/og/posts/WEhhiXOjN.png
og:image:alt: Postgres LISTEN/NOTIFY actually scales
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.

# Postgres LISTEN/NOTIFY actually scales

**[Hacker News](https://daily.dev/sources/hn)** · 6 min read · 34 upvotes · 2 comments

## Summary

Postgres LISTEN/NOTIFY has a reputation for poor scalability due to a global exclusive lock taken during NOTIFY commits. This lock serializes all transactions containing notifications, preventing group commit optimizations and capping throughput at ~2.9K writes/second. The root cause is Postgres's guarantee that notifications are sent in transaction commit order, requiring a global queue. The fix: buffer notifications in memory and flush them in batches, so the global lock is only taken periodically rather than on every write. A polling fallback handles cases where buffered notifications are lost on process crash. This approach achieves 60K stream writes per second on a single Postgres server with 15-100ms latency — a 20x improvement.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.dbos.dev/blog/postgres-listen-notify-scalability>

## Community take

How the wider developer community reacted, aggregated from 2 discussions and 40 comments across hackernews, lobsters (as of 2026-07-25).

**TL;DR:** The community is cautiously interested in the DBOS/Postgres LISTEN/NOTIFY scaling approach but debates whether the optimization (application-side batching) is a genuine solution or just a workaround that sacrifices delivery guarantees, and whether the benchmark hardware (96-core, 384GB RAM server) makes the results realistic for most teams.

**Sentiment:** 40% positive · 40% mixed · 20% skeptical

**The case for**

- Application-side buffering and batching is a general-purpose optimization that doesn't require patching Postgres itself.
- LISTEN/NOTIFY integrates tightly with the rest of the DB, avoids an extra service to operate, and is plenty sufficient for many real-world workloads.
- Cache invalidation is a particularly good fit for LISTEN/NOTIFY since its scale is intrinsically tied to the write rate of the database.

**The pushback**

- The benchmark was run on a very large server (96 cores, 384 GB RAM), which is not representative of typical deployments and was not prominently disclosed.
- The optimization appears to trade away delivery guarantees and push notification logic into the application layer, complicating future changes.
- Real-world experience shows that building queues on top of PG internals creates operational and cognitive overhead, especially as teams grow.
- Burst traffic, not steady-state throughput, is what typically breaks systems, and the post doesn't address that.
- The code complexity of the proposed solution raises concerns about debuggability and maintainability.

**By community**

- hackernews (mixed): Commenters appreciate the general insight but push back on the benchmark hardware, the definition of 'scale,' and whether application-side batching is a real fix or just a workaround.
- lobsters (skeptical): The single commenter finds the article confusing and argues the approach sacrifices key delivery guarantees, suggesting a proper DB-level solution (e.g., NOTIFY UNORDERED) would be preferable.

**Hottest debate:** Whether application-side batching that relaxes delivery guarantees truly 'scales' LISTEN/NOTIFY or just sidesteps the problem while introducing new complexity.

**Open questions**

- Would a Postgres-native option like NOTIFY UNORDERED (skipping the global lock without sacrificing other guarantees) be a better long-term solution?
- How does the approach handle burst traffic rather than steady-state throughput?
- What are the exact delivery semantics lost when using the batching optimization, and how should applications compensate?

**Highlights**

> I once was the CTO of a company that serviced about 100k requests per day across all our services. We grew to millions and eventually 10's of millions, but, somewhere along the way, an engineer on our team decided he wanted to build a queue off LISTEN/NOTIFY semantics in order to take advantage of strong consistency with the rest of our data model, which seemed reasonable given LISTEN/NOTIFY is not that hard to understand and we did need consistency guarantees for this workflow and this would remove the need for yet another place data got stored and transfered. In practice, this eventually ended up being very awkward because extending the functionality (since we had "built" it) and had to work around internal pg semantics (we should have just moved off much sooner). It also did not scale well. We ended up getting a ton of disk contention on our RDS instance in non-obvious ways, and the vacuum runs on that table was a nightmare. Additionally, it was hard to get other engineers to really debug and take ownership of the system because they automatically viewed a queue (very easy to understand) implemented in a foreign way (off pg internals) as something "scary". It was emotional, not rational, but we are emotional beings, and I do not blame them. These were good engineers with a lot of other things on their plates. Obviously, this is all hand-wavy without discussing the internal schema, indeces, etc. that we had set up, but my main takeaway with core technology from this experience was to always reach for the dumb, expected, simple thing. Even if it adds another moving piece in the infra stack. Unless I need very strong data consistency guarantees, it's always better to use something like SQS, Redis queues, etc. where the understanding is that it is just a queue (or at least the API contract suggests simplicity), and then everything needs to work around it. The fewer mechanistic responsibilities per core data store, the better in my experience.
> — [vhiremath4 on hackernews · 2 comments](https://news.ycombinator.com/item?id=49043376)

> I think a lot of these kind of posts are standalone assessment of your problems, understanding and solutions. Its debatable to term something as lack of expertise if one is trying to work with default settings of a tool and expecting a certain performance. Everyone is doing a continuous learning with the failures. 1. What I find interesting is that the experiment seems to be using a DB server with 96 cores, 384 GB RAM (https://github.com/dbos-inc/dbos-postgres-benchmark/blob/mai...). This is very critical part of any such experiment, it should have been called out. The database is vertically scalable and that too has its limits 2. Who is making connection, and from where has its own impact on performance and overall latency 3. 60k may seem big number, however in real world the things which bring the systems down are the bursts of traffic, not the regular traffic. Personally I would never start with such a big server unless I am a big business. Its > 100K cost for one production DB cluster if I include read replicas and cross region redundancy
> — [sandeepkd on hackernews](https://news.ycombinator.com/item?id=49041452)

> This article is very confusing because it seems to be saying that there is a way to make NOTIFY performant by (apparently) patching PostgreSQL to throw away all its guarantees including the delivery guarantees. But I’m not sure if it’s a patch or just a different way to use notify, because it’s not clear? And I don’t speak Python. But given the lack of delivery guarantees and the fact that the clients now need to fall back to occasional polling, ISTM we may as well just post notifications out of band from the app. Or, perhaps that’s what they’re doing, but just with NOTIFY. The thing is that the trigger based notify is useful because you can keep your DML inside the DB. Anything that causes a change causes a NOTIFY. Pushing notify semantics up to the application layer causes all sorts of complications for future changes. If we’re patching PG I think a better solution would be something like NOTIFY UNORDERED where we tell PG that we don’t care about the order of notifies so the database doesn’t have to take the global lock, but the other guarantees are maintained. Or maybe I’m just missing something.
> — [doctor\_eval on lobsters · 1 points](https://lobste.rs/s/ighdht/postgres_listen_notify_actually_scales#c_cws7a1)

> So in summary, Postgres NOTIFY actually scales if you make your application not write to the database? That's a bit of a tough sell...
> — [d9127acbd6fe281 on hackernews](https://news.ycombinator.com/item?id=49042048)

> I continue to love DBOS for how it just leverages Postgres (and now SQLite) properly. It's effortless to drop into an existing CRUD stack. Once you start down the "durable workflows" path, you start seeing them everywhere. My latest experiments are treating individual emails as durable workflows, where you, the people you're communicating with, agents and tools like GitHub or Attio all take turns in the flow. https://housecat.com/blog/gmail-durable-workflows-sandbox-vm
> — [nzoschke on hackernews](https://news.ycombinator.com/item?id=49040676)

**Source threads**

- [hackernews](https://news.ycombinator.com/item?id=49040296) · 61 points · 39 comments
- [lobsters](https://lobste.rs/s/ighdht/postgres_listen_notify_actually_scales) · 10 points · 1 comments

## Community discussion

Top comments from developers on daily.dev.

**@hzmalix** · 1 upvotes

> Great breakdown of the exclusive lock bottleneck!

**@gaburayondev** · 0 upvotes

> The root cause explanation is the useful part here — most people know LISTEN/NOTIFY "doesn't scale" but not why. A global lock to preserve commit-order guarantees makes sense once you see it, and it explains why this isn't a config tweak, it's an architectural workaround. Batching + a crash-recovery polling fallback is a pragmatic tradeoff: you give up a bit of latency for a 20x throughput win, and you don't lose correctness on process failure. 60K writes/sec out of a single Postgres instance for this is genuinely impressive without reaching for Kafka or Redis.

## Similar posts on daily.dev

- [LISTEN Carefully: How NOTIFY Can Trip Up Your Database](https://daily.dev/posts/listen-carefully-how-notify-can-trip-up-your-database-vkypsjscr) · Planet PostgreSQL · 3 upvotes · 0 comments
- [All Your GUCs in a Row: notify\_buffers](https://daily.dev/posts/all-your-gucs-in-a-row-notify-buffers-15fp62gxl) · Planet PostgreSQL · 1 upvotes · 0 comments
- [Video Conferencing with Postgres — PlanetScale](https://daily.dev/posts/video-conferencing-with-postgres-planetscale-tfdk2qio7) · Lobsters · 9 upvotes · 0 comments

---

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

[View this post on daily.dev](https://daily.dev/posts/postgres-listen-notify-actually-scales-wehhixojn)

```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":"Postgres LISTEN/NOTIFY actually scales","url":"https://daily.dev/posts/postgres-listen-notify-actually-scales-wehhixojn","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/postgres-listen-notify-actually-scales-wehhixojn"},"datePublished":"2026-07-24T19:50:00.647Z","dateModified":"2026-07-25T08:17:27.618Z","description":"Postgres LISTEN/NOTIFY has a reputation for poor scalability due to a global exclusive lock taken during NOTIFY commits. This lock serializes all transactions...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/f7a9fcc97991618c467cee58b7f22672?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/f7a9fcc97991618c467cee58b7f22672?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Hacker News","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":"Hacker News","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/hn","url":"https://daily.dev/sources/hn"},"commentCount":2,"discussionUrl":"https://daily.dev/posts/postgres-listen-notify-actually-scales-wehhixojn","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":34},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":2}],"keywords":"performance,postgresql","timeRequired":"PT6M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Hacker News","item":"https://daily.dev/sources/hn"},{"@type":"ListItem","position":3,"name":"Postgres LISTEN/NOTIFY actually scales"}]}
{"@context":"https://schema.org","@type":"WebPage","@id":"https://daily.dev/posts/postgres-listen-notify-actually-scales-wehhixojn","comment":[{"@type":"Comment","text":"Great breakdown of the exclusive lock bottleneck!","datePublished":"2026-07-27T04:33:17.495Z","url":"https://daily.dev/posts/WEhhiXOjN#c-NFVExC0XK","author":{"@type":"Person","name":"Muhammad Hammad Zafar","url":"https://daily.dev/hzmalix","image":"https://avatars.githubusercontent.com/u/48489738?v=4"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":1}},{"@type":"Comment","text":"The root cause explanation is the useful part here — most people know LISTEN/NOTIFY “doesn’t scale” but not why. A global lock to preserve commit-order guarantees makes sense once you see it, and it explains why this isn’t a config tweak, it’s an architectural workaround. Batching + a crash-recovery polling fallback is a pragmatic tradeoff: you give up a bit of latency for a 20x throughput win, and you don’t lose correctness on process failure. 60K writes/sec out of a single Postgres instance for this is genuinely impressive without reaching for Kafka or Redis.","datePublished":"2026-07-29T09:04:17.169Z","url":"https://daily.dev/posts/WEhhiXOjN#c-8yKCgXzBQ","author":{"@type":"Person","name":"Gabu Rayon Dev","url":"https://daily.dev/gaburayondev","image":"https://media.daily.dev/image/upload/s--5hPC52y_--/f_auto/v1773412842/avatars/avatar_8fkdziGASnSSBES6c4Ml9?_a=BAMAMiiu0"}}]}
```

