Files
common/database/pgdb/CLAUDE.md
Ask Bjørn Hansen 614cbf8097 feat(pgdb): add PG* environment variable fallback in OpenPool
When no DATABASE_URI or config file is found, fall through to
pgxpool.ParseConfig("") which natively reads standard PG* variables
(PGHOST, PGUSER, PGPASSWORD, PGDATABASE, etc.). This removes
unnecessary ceremony in CI and container environments where PG* vars
are already set.
2026-02-21 00:34:09 -08:00

3.9 KiB

pgdb - Native PostgreSQL Connection Pool

Primary package for PostgreSQL connections using native pgx pool (*pgxpool.Pool). Provides better performance and PostgreSQL-specific features compared to database/sql.

Usage

Basic Example

import (
    "context"
    "go.ntppool.org/common/database/pgdb"
)

func main() {
    ctx := context.Background()

    // Open pool with default options
    pool, err := pgdb.OpenPool(ctx, pgdb.DefaultPoolOptions())
    if err != nil {
        log.Fatal(err)
    }
    defer pool.Close()

    // Use the pool for queries
    row := pool.QueryRow(ctx, "SELECT version()")
    var version string
    row.Scan(&version)
}

With Custom Config File

pool, err := pgdb.OpenPoolWithConfigFile(ctx, "/path/to/database.yaml")

With Custom Pool Settings

opts := pgdb.DefaultPoolOptions()
opts.MaxConns = 50
opts.MinConns = 5
opts.MaxConnLifetime = 2 * time.Hour

pool, err := pgdb.OpenPool(ctx, opts)

Configuration Format

postgres:
  host: localhost
  port: 5432
  user: myuser
  pass: mypassword
  name: mydb
  sslmode: prefer

Legacy: Flat Format (backward compatible)

host: localhost
port: 5432
user: myuser
pass: mypassword
name: mydb
sslmode: prefer

Configuration Options

PoolOptions

Defaults match pgxpool defaults:

  • ConfigFiles - List of config file paths to search (default: database.yaml, /vault/secrets/database.yaml)
  • MinConns - Minimum connections (default: 0)
  • MaxConns - Maximum connections (default: 4)
  • MaxConnLifetime - Connection lifetime (default: 1 hour)
  • MaxConnIdleTime - Idle timeout (default: 30 minutes)
  • HealthCheckPeriod - Health check interval (default: 1 minute)

For higher connection limits, set via PoolOptions or URI query parameter ?pool_max_conns=25.

PostgreSQL Config Fields

  • host - Database host (required)
  • user - Database user (required)
  • pass - Database password
  • name - Database name (required)
  • port - Port number (default: 5432)
  • sslmode - SSL mode: disable, allow, prefer, require, verify-ca, verify-full (default: prefer)

Environment Variables

  • DATABASE_URI - PostgreSQL connection URI (takes precedence over all other methods)
  • DATABASE_CONFIG_FILE - Override config file location
  • Standard PG* variables (PGHOST, PGUSER, PGPASSWORD, PGDATABASE, PGPORT, PGSSLMODE, etc.) - used as fallback when no config file is found; parsed natively by pgx

URI Format

Standard PostgreSQL URI format:

postgresql://user:password@host:port/database?sslmode=require&pool_max_conns=10

Pool settings can be included in the URI query string:

  • pool_max_conns, pool_min_conns
  • pool_max_conn_lifetime, pool_max_conn_idle_time
  • pool_health_check_period

When using DATABASE_URI, pool settings come from the URI. Since PoolOptions defaults match pgxpool defaults, behavior is consistent whether using URI or config files.

Example with CloudNativePG:

# Mount the secret's 'uri' key as DATABASE_URI
env:
  - name: DATABASE_URI
    valueFrom:
      secretKeyRef:
        name: mydb-app
        key: uri

When to Use

Use pgdb.OpenPool() (this package) when:

  • You need native PostgreSQL features (LISTEN/NOTIFY, COPY, etc.)
  • You want better performance
  • You're writing new PostgreSQL code

Use database.OpenDB() (sql.DB) when:

  • You need database-agnostic code
  • You're using SQLC or other tools that expect database/sql
  • You need to support both MySQL and PostgreSQL

Security

This package avoids password exposure by:

  1. Never constructing DSN strings with passwords
  2. Setting passwords separately in pgx config objects
  3. Validating all configuration before connection

See Also