we moved our django app behind pgbouncer transaction pooling a few days ago and the surprise wasn't SET so much as queryset.iterator(). it relies on server side cursors, which don't survive being pooled, so we had to disable it everywhere and let it fall back to client side. also had to move statement_timeout out of the app's connection options into the pooler's own connect query, since libpq startup params just get…
Handling cursors is tough - they are very much session-level objects, so even if we, say, pinned your client while it uses that cursor, which would work, that would decrease the performance of connection pooling overall. So, what's better, breaking your app initially so you know to remove that feature, or letting it work silently while the connection pool isn't 100% in transaction mode? Tough call.
Why we built yet another Postgres connection pooler
41–50 of 74 posts
Re: Why we built yet another Postgres connection pooler
#42Earlier quoted context omitted.
Looked it up, says 'Will be released as an open source project' but announcement was in July 2025 and no public repo yet which is strange, so time will tell if they will stick to this. https://planetscale.com/blog/planetscale-for-postgres#vitess... https://planetscale.com/neki ... Supabase one is open from start: https://github.com/multigres/multigres https://multigres.com/
We are already moving Neki customers into production. Nobody else is even close. PlanetScale doesn't spend our days yapping about what we are going to do. We just do it.
Re: Why we built yet another Postgres connection pooler
#43Re: Why we built yet another Postgres connection pooler
#44Re: Why we built yet another Postgres connection pooler
#45Re: Why we built yet another Postgres connection pooler
#46we moved our django app behind pgbouncer transaction pooling a few days ago and the surprise wasn't SET so much as queryset.iterator(). it relies on server side cursors, which don't survive being pooled, so we had to disable it everywhere and let it fall back to client side. also had to move statement_timeout out of the app's connection options into the pooler's own connect query, since libpq startup params just get…
Handling cursors is tough - they are very much session-level objects, so even if we, say, pinned your client while it uses that cursor, which would work, that would decrease the performance of connection pooling overall. So, what's better, breaking your app initially so you know to remove that feature, or letting it work silently while the connection pool isn't 100% in transaction mode? Tough call.
Re: Why we built yet another Postgres connection pooler
#47we moved our django app behind pgbouncer transaction pooling a few days ago and the surprise wasn't SET so much as queryset.iterator(). it relies on server side cursors, which don't survive being pooled, so we had to disable it everywhere and let it fall back to client side. also had to move statement_timeout out of the app's connection options into the pooler's own connect query, since libpq startup params just get…
Using server-side cursors is a sign of bad design. You use the PostgreSQL server's resources as a cache when you're fetching and processing stuff row by row, which is very bad. Just get the data you requested in the first place in one go and do your stuff in your app. Or process all data on the server and then get the processed data in one batch as well.
the honest knock on the streaming kind isn't "bad design", it's that it holds a portal open server-side, which is why it can't survive transaction pooling. so the pooler-friendly fix isn't one giant fetch, it's keyset pagination (where id > last limit n), stateless and constant memory, which is what we moved those paths to.
Re: Why we built yet another Postgres connection pooler
#48What really interests me most is the sharding and the possibility of using this for multitenancy - is the hooks / plugin architecture sufficient so you can run a small sidecar to add shards or tenants to the TOML file dynamically? Would be a game changer.
Re: Why we built yet another Postgres connection pooler
#49It's awesome to see AGPL instead of the horrible BSL variants that have been going around.
Re: Why we built yet another Postgres connection pooler
#50> Since connection poolers reuse connections between clients, the connection state of one client “leaks” into the connection state of another. Wow this is very bad. This actually happens in typical Postgres setups?
It's not unique to postgres, as others have said; the same thing can happen with e.g. MySQL poolers/proxies/etc., since the behavior of the connection can be changed dynamically and it persists for the lifetime of the connection. Example: legacy client A connects to MySQL via the bouncer and says 'I want all of our conversations to use latin-1, not utf-8'. This changes the character set that MySQL parses queries with…
I believe ProxySQL does exactly that:
* https://proxysql.com/documentation/mysql-prepared-statements...