Skip to main content

Overview

PgDog is a high-performance PostgreSQL connection pooler, load balancer, and sharding proxy written in Rust. It sits transparently in front of one or more PostgreSQL instances and appears to clients as a standard PostgreSQL server — no application code changes required, only a connection string update. PgDog parses SQL queries to automatically route writes (INSERT, UPDATE, DELETE, DDL) to a primary backend and distribute SELECT queries across replicas. Works with any PostgreSQL-compatible backend including the Control Plane PostgreSQL and PostgreSQL Highly Available templates, or any external PostgreSQL endpoint.

Architecture

  • PgDog workload — Stateless proxy that multiplexes client connections into a smaller pool of real backend connections. Scales horizontally; each replica maintains its own connection pool.
  • pgdog.toml — Main configuration rendered as a secret and mounted at startup. Defines backend databases, pool settings, timeouts, and load balancing strategy.
  • users.toml — Credentials configuration rendered as a separate secret. Defines which users can connect to PgDog and which backend databases they map to.

What Gets Created

  • Standard PgDog Workload — Stateless proxy workload listening on port 6432.
  • Identity & Policy — Identity for the workload with access to credential secrets.
  • Secrets — Two opaque secrets: one for pgdog.toml (database and pooling config) and one for users.toml (user credentials).
This template does not create a GVC or a PostgreSQL instance. Deploy it into an existing GVC and point it at an existing PostgreSQL backend.

Prerequisites

This template has no external prerequisites. To install, follow the instructions for your preferred method:

UI

Browse, install, and manage templates visually

CLI

Manage templates from your terminal

Terraform

Declare templates in your Terraform configurations
Pulumi Icon Streamline Icon: https://streamlinehq.com

Pulumi

Declare templates in your Pulumi programs

Configuration

The default values.yaml for this template:
image: ghcr.io/pgdogdev/pgdog:v0.1.45

resources:
  cpu: 500m
  memory: 256Mi
  minCpu: 100m
  minMemory: 128Mi

replicas: 1

pooling:
  mode: transaction          # options: transaction, session
  defaultPoolSize: 10        # max server connections per pool
  minPoolSize: 1             # minimum idle connections kept open
  workers: 2                 # async threads; recommend 2× vCPU count

timeouts:
  connect: 5000              # time to establish a backend connection (ms)
  checkout: 5000             # max time a client waits for a free connection (ms)
  idle: 60000                # idle server connections closed after this (ms)
  query: 0                   # per-query timeout; 0 = disabled

loadBalancing:
  strategy: least_active_connections  # options: random, round_robin, least_active_connections
  readWriteSplit: include_primary

databases:
  - name: mydb
    host: postgres.example.com
    port: 5432
    role: primary            # options: primary, replica, auto

users:
  - name: myuser
    password: mypassword
    database: mydb

admin:
  database: admin
  user: admin
  password: changeme

auth:
  type: scram

logging:
  format: text               # options: text, json, json_flattened
  level: info

publicAccess:
  enabled: false
  # address: pgdog.example.com

internalAccess:
  type: same-gvc             # options: none, same-gvc, same-org, workload-list
  workloads: []

Backend Databases

The databases list defines the PostgreSQL backends PgDog proxies. Each entry maps to a [[databases]] block in pgdog.toml. Multiple entries sharing the same name form a cluster — PgDog routes writes to primary backends and distributes reads across replica backends.
databases:
  - name: mydb
    host: my-postgres.my-gvc.cpln.local
    port: 5432
    role: primary

  - name: mydb
    host: replica-1.my-patroni-postgres.aws-us-east-1.my-gvc.cpln.local
    port: 5432
    role: replica

  - name: mydb
    host: replica-2.my-patroni-postgres.aws-us-east-1.my-gvc.cpln.local
    port: 5432
    role: replica
roleBehavior
primaryReceives all write queries (INSERT, UPDATE, DELETE, DDL)
replicaReceives read queries (SELECT) distributed by the load balancing strategy
autoPgDog detects the role via pg_is_in_recovery() at connection time
Using with the PostgreSQL template — Set host to {release-name}-postgres.{gvc}.cpln.local. Using with the PostgreSQL Highly Available template — Point the primary entry at the HA proxy ({release-name}-postgres-ha-proxy.{gvc}.cpln.local) and add replica entries using the replicaDirect hostnames (replica-{n}.{release-name}-postgres-ha.{location}.{gvc}.cpln.local).

Users

The users list defines which clients can connect to PgDog. Each entry maps to a [[users]] block in users.toml. The database field must match a name from the databases list.
users:
  - name: myuser
    password: mypassword
    database: mydb
PgDog uses the name and password to authenticate incoming clients, then uses the same credentials to connect to the backend PostgreSQL server.

Connection Pooling

ParameterDefaultDescription
pooling.modetransactionPool mode: transaction or session
pooling.defaultPoolSize10Maximum real Postgres connections per pool
pooling.minPoolSize1Minimum idle connections kept open
pooling.workers2Async threads; recommended value is 2× vCPU count
Pool ModeDescription
transactionBackend connection held only for the duration of a transaction, then returned to the pool. Best for most web and API workloads. Not compatible with SET variables, temporary tables, or advisory locks.
sessionBackend connection held for the entire client session. Compatible with all Postgres features. Increase defaultPoolSize to match expected concurrent client count.

Load Balancing

StrategyDescription
least_active_connectionsRoutes reads to the replica with the fewest active connections. Recommended for most workloads.
round_robinDistributes reads evenly across all replicas in rotation.
randomSelects a replica at random for each read query.
readWriteSplit: include_primary allows the primary to also serve reads when no replicas are available.

Timeouts

All timeout values are in milliseconds.
ParameterDefaultDescription
timeouts.connect5000Time to establish a backend connection
timeouts.checkout5000Max time a client waits for a free pool connection
timeouts.idle60000Idle backend connections closed after this duration
timeouts.query0Per-query timeout; 0 disables it

Admin Database

PgDog exposes an internal admin database for stats and introspection.
admin:
  database: admin
  user: admin
  password: changeme
Always set admin.password explicitly. If omitted, PgDog generates a random password at each startup, making the admin database inaccessible across restarts.
Connect to the admin database with any PostgreSQL client:
PGPASSWORD=<admin.password> psql \
  -h {release-name}-pgdog.{gvc}.cpln.local \
  -p 6432 \
  -U admin \
  -d admin

Access

  • internalAccess.type — Controls which workloads can reach PgDog internally: same-gvc, same-org, workload-list, or none.
  • publicAccess.enabled — When true, Control Plane provisions a public TCP load balancer. The assigned hostname (e.g. pgdog-name-hash.cpln.app:6432) is visible in the Control Plane console or via cpln workload get <name> -o yaml.
  • publicAccess.address — Optional custom domain to attach when public access is enabled.

Scaling

PgDog is stateless and scales horizontally by increasing replicas. Each replica maintains its own connection pool — scale pooling.defaultPoolSize down proportionally when adding replicas to avoid overloading the backend with too many open connections.

Logging

logging:
  format: text   # options: text, json, json_flattened
  level: info    # RUST_LOG syntax, e.g. info, debug, pgdog=debug

Connecting

Applications connect to PgDog exactly as they would connect to PostgreSQL — PgDog implements the full PostgreSQL wire protocol.
SettingValue
Host{release-name}-pgdog.{gvc}.cpln.local
Port6432
DatabaseA name from your databases list
UsernameA name from your users list
PasswordThe matching password from your users list
Example connection string:
postgresql://myuser:mypassword@{release-name}-pgdog.{gvc}.cpln.local:6432/mydb

Important Notes

  • PgDog does not manage PostgreSQL — it is a proxy only. Deploy a PostgreSQL backend separately before pointing PgDog at it.
  • Port 6432, not 5432 — PgDog listens on port 6432. Update application connection strings accordingly.
  • Transaction mode and session features — If your application uses SET variables, prepared statements, temporary tables, or advisory locks, use pooling.mode: session instead of transaction.
  • Admin password — Always set admin.password explicitly. Omitting it causes PgDog to generate a random password at each restart, making the admin database unreachable across restarts.
  • Scaling and pool sizing — Each PgDog replica maintains its own pool. When scaling replicas, reduce pooling.defaultPoolSize proportionally to avoid opening too many total connections to the backend.

External References

PgDog Documentation

Official PgDog configuration and architecture reference

PgDog GitHub

Source code and issue tracker

PostgreSQL Template

Single-instance PostgreSQL template for use with PgDog

PostgreSQL Highly Available Template

HA PostgreSQL with Patroni — primary + replicas for PgDog read/write splitting