Self-hosted service
pgdogdev/pgdog avatar
pgdogdev/pgdog

PgDog: a PostgreSQL pooler, load balancer and sharder written in Rust

PostgreSQL connection pooler, load balancer and database sharder.

5,539 stars292 forksRustAGPL-3.0

At a glance

What is it?
PgDog sits between your application and PostgreSQL, pooling connections, distributing queries across replicas and sharding whole databases. It is aimed at teams already running Postgres at a scale where one primary and one connection string stop being enough.
Who is it for?
Adopt PgDog if you already run PostgreSQL with replicas or shards and want pooling, L7 read/write routing and sharding behind one endpoint, and you accept AGPL-3.0 terms for a network-facing service. Do not adopt it if you need a mature, widely deployed pooler with a long operational record, or if you cannot run a second process in front of your database.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

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

Editorial analysis

What PgDog solves, and who ends up running it

PostgreSQL accepts one connection per backend process. An application fleet that opens thousands of connections therefore forces the server to hold thousands of processes, and the memory and context-switching cost lands on the database. PgDog is a proxy that sits in front of Postgres and multiplexes many client connections onto a small number of server connections. The README describes it as an open source proxy for scaling PostgreSQL, with connection pooling, load balancing and sharding as the three jobs.

The intended user is not someone running a single Postgres instance behind one application. It is a team that already has a primary and replicas, or has begun splitting data across shards, and now needs a layer that understands the Postgres wire protocol rather than a generic TCP proxy. The README claims it can manage thousands of connections on commodity hardware, which is the same claim every pooler makes; what distinguishes the design here is that the proxy parses queries instead of only forwarding bytes. That parsing is what makes read/write routing and sharding possible at all.

Transaction pooling, SET statements and the parser at the centre

PgDog supports transaction and session pooling, the same modes PgBouncer offers. In transaction mode a server connection is handed to a client only for the duration of a transaction, so a few server connections serve many clients. The README states that unlike PgBouncer, PgDog can parse and handle SET statements and startup options, so session state is applied correctly when a server connection is shared between clients that expect different parameters. That is a real difference in mechanism: the pooler has to track per-client state and replay it onto whichever backend connection it borrows.

The same parser drives the load balancer. PgDog uses pg_raw_parse, which the README says includes the PostgreSQL native parser. Because queries are parsed, PgDog can classify writes such as INSERT, UPDATE and CREATE TABLE and send them to the primary, while SELECT statements go to replicas. Applications can point at one PgDog endpoint for both reads and writes, which removes the usual two-connection-string setup. Transactions are the exception the README calls out: a transaction can contain multiple statements, so in a primary and replica configuration PgDog routes the whole transaction to the primary unless the client opens it with BEGIN READ ONLY, in which case it goes to a replica.

Connection recovery is the other place where the mechanism shows. The README mentions automatic abandoned transaction rollbacks and connection re-synchronization, aimed at avoiding connection churn when an application crashes mid-transaction. The README does not document how long a connection is held before PgDog decides a transaction was abandoned, so that threshold is something to check in the configuration reference rather than assume.

Installing PgDog and running the Docker demo

The README gives three deployment paths. Kubernetes uses a Helm chart from the pgdogdev repository. AWS users can take the same Helm chart on EKS or a Terraform module that deploys PgDog on ECS. The fastest way to see the thing work is the Docker Compose file in the repository root, which starts PgDog plus three Postgres 18 shards.

Install the chart repository and the chart with these two commands, which the README lists under Quick start:

bash
helm repo add pgdogdev https://helm.pgdog.dev
helm install pgdog pgdogdev/pgdog

For the local demo, the README says to install Docker Compose and run the compose file from the repository root. That starts the pgdog service from ghcr.io/pgdogdev/pgdog:main, publishing port 6432, alongside shard_0, shard_1 and shard_2.

bash
docker-compose up

Once it is up, connect with psql on port 6432 using the postgres user and password. The README shows exactly this command:

bash
PGPASSWORD=postgres psql -h 127.0.0.1 -p 6432 -U postgres

The demo ships with three shards and two sharded tables, users and payments. The README's example inserts one row into each and reads them back by the shard key, id for users and user_id for payments:

sql
INSERT INTO users (id, email) VALUES (1, '[email protected]');
INSERT INTO payments (id, user_id, amount) VALUES (1, 1, 100.0);

SELECT * FROM users WHERE id = 1;
SELECT * FROM payments WHERE user_id = 1;

If you would rather run PgDog against a database on the same machine, the README's minimal configuration needs two files. pgdog.toml carries the port, pool size and database host:

toml
[general]
port = 6432
default_pool_size = 10

[[databases]]
name = "pgdog"
host = "127.0.0.1"

users.toml carries the credentials. The README is explicit about the failure mode here: a database in pgdog.toml with no matching user in users.toml gets no connection pool, and nobody can connect to it.

toml
[[users]]
name = "alice"
database = "pgdog"
password = "hunter2"

Load balancing, health checks and where failover stops

The load balancer turns on by itself when a database name appears more than once in pgdog.toml with different hosts. The README shows a prod database declared twice, once with role = "primary" on 10.0.0.1 and once with role = "replica" on 10.0.0.2. Three strategies are available: round robin, random and least active connections. PgDog describes itself as an OSI Level 7 load balancer, which is accurate in the sense that routing decisions come from parsed SQL, not from connection counts alone.

Health checks maintain a live list of healthy hosts. A host that fails a check leaves the rotation and queries are rerouted to the remaining replicas. The README compares this to an HTTP load balancer, and the comparison holds up to a point: the check is about reachability and liveness, not about replication lag, so a replica that is up but far behind still receives reads.

Failover is the feature to read carefully. PgDog monitors replication state and can redirect writes to a different database when a replica is promoted. The README states plainly that this does not replace tools like Patroni that orchestrate failovers, and positions PgDog as something you run alongside Patroni, RDS or another managed Postgres host to move live traffic gracefully. Enabling it means setting every database role to auto and setting lsn_check_delay, which the README's example sets to 0. If you expect PgDog to decide when to promote, you are reading the wrong section of the documentation.

Where PgDog is the wrong tool

The first limitation is version maturity. The releases in the repository are all in the 0.1.x line, with v0.1.59 published on 2026-09-17, and the last push to main was on 2026-09-22. That is a project moving quickly, which cuts both ways: features arrive, and configuration keys can change between minor releases. The repository keeps a CHANGELOG.md, and reading it before an upgrade is the cheapest insurance available.

The second limitation is architectural. PgDog is another process in the query path. Every query passes through it, so its availability becomes your database's availability, and its parser becomes a component you have to trust with your SQL. If your workload is a single Postgres instance with an application that already uses a small connection pool, PgDog adds a hop and a configuration surface for no gain. The README's own minimal example is a single user against a local database; that setup works, but it does not need a pooler.

The third is the boundary around failover, already noted: PgDog reacts to replication state, it does not orchestrate promotion. Teams that want the proxy to be the failover authority will be disappointed. And sharding is not free either. Splitting tables across shards changes what queries are routable, and the README does not document the full set of sharding constraints, so the sharding documentation is where to look before designing a schema around it.

PgDog compared with PgBouncer and PgCat

PgBouncer is the reference point for connection pooling, and the README draws the comparison directly: PgDog supports transaction and session pooling like PgBouncer, but adds parsing and handling of SET statements and startup options. That is the concrete difference in approach. PgBouncer is a protocol-aware pooler that largely forwards queries; PgDog parses them, which is what lets it route reads and writes and shard. If all you need is connection multiplexing, PgBouncer has a much longer operational history and no sharding to configure.

PgCat is the closer comparison, and it is the one people search for. Both are Rust proxies for PostgreSQL that pool, load balance and shard, so the choice is not about feature checkboxes but about which project's configuration model and release cadence fit your team. The README documents PgDog's two-file configuration, its parser, its three balancing strategies and its failover boundary; it does not contain a feature-by-feature comparison with PgCat, so treat any claim that one is strictly better as unverified. Patroni is a different kind of tool entirely: it orchestrates Postgres failover, and the README explicitly says PgDog does not replace it. They are complements, not alternatives.

Licence and the cost of keeping it current

PgDog is licensed under AGPL-3.0. That matters more for a proxy than for a library, because the licence's network clause applies to software users interact with over a network. If you modify PgDog and expose it to your users, the AGPL's source-availability obligations are worth understanding before you ship. This is not legal advice, and the repository also ships an enterprise edition with its own changelog in CHANGELOG-ENTERPRISE.md and documentation under the enterprise_edition path, so teams with commercial requirements should read both licences rather than assume the open source terms are the only ones on offer.

Upgrade cost is real but bounded. The configuration lives in two TOML files, pgdog.toml and users.toml, and the workspace is split into crates such as pgdog-config, pgdog-plugin and pgdog-stats, with plugins built as shared objects. The Dockerfile shows that the primary-only-tables plugin is compiled separately and copied to /usr/lib. Any deployment that relies on a plugin has to rebuild it alongside the proxy, which is the kind of coupling that shows up during an upgrade and not before.

Editorial conclusion

Adopt PgDog if you already run PostgreSQL with replicas or shards and want pooling, L7 read/write routing and sharding behind one endpoint, and you accept AGPL-3.0 terms for a network-facing service. Do not adopt it if you need a mature, widely deployed pooler with a long operational record, or if you cannot run a second process in front of your database. Before rolling it out, verify which configuration keys your target release actually accepts, confirm that every database in pgdog.toml has a matching entry in users.toml, and check the CHANGELOG.md for the behaviour that changed since the version you tested.

Frequently asked questions

What is PgDog?

PgDog is an open source proxy for scaling PostgreSQL, written in Rust. It provides connection pooling, load balancing across replicas and sharding of entire databases.

What are the key differences between PgDog and PgBouncer?

Both support transaction and session pooling, but the README states that PgDog can parse and handle SET statements and startup options so session state is set correctly when server connections are shared. PgDog also adds a load balancer and sharding, which PgBouncer does not provide.

What are the key differences between PgCat and PgDog, and which one is better?

Both are Rust proxies for PostgreSQL that pool connections, balance load and shard. The repository does not contain a feature-by-feature comparison, so the choice comes down to each project's configuration model and release cadence rather than a documented verdict.

How does PgDog relate to Patroni?

PgDog monitors replication state and can redirect writes when a replica is promoted, but the README says this does not replace tools like Patroni that actually orchestrate failovers. PgDog is meant to run alongside Patroni or a managed Postgres host to move live traffic.

Official sources

  1. License: AGPL-3.0
  2. pgdogdev/pgdog on GitHub
  3. Project website
  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/pgdogdev-pgdog.svg)](https://hysenlabs.com/projects/pgdogdev-pgdog)