Go: pgx
Connect Go to a CapyDB Postgres database with pgx and pgxpool: the pooled URL and statement caching, and the direct URL for golang-migrate, goose or Atlas.
Environment
export DATABASE_URL="postgres://user:password@host:6432/db?sslmode=verify-full"
export DATABASE_DIRECT_URL="postgres://user:password@host:5432/db?sslmode=verify-full"pgxpool
package main
import (
"context"
"os"
"github.com/jackc/pgx/v5/pgxpool"
)
func main() {
config, err := pgxpool.ParseConfig(os.Getenv("DATABASE_URL"))
if err != nil {
panic(err)
}
config.MaxConns = 10
pool, err := pgxpool.NewWithConfig(context.Background(), config)
if err != nil {
panic(err)
}
defer pool.Close()
var now string
if err := pool.QueryRow(context.Background(), "SELECT now()::text").Scan(&now); err != nil {
panic(err)
}
}Pooled URL and statement caching
pgx caches prepared statements by default, which breaks behind transaction pooling. On the pooled URL, switch to simple protocol:
config.ConnConfig.DefaultQueryExecMode = pgx.QueryExecModeSimpleProtocolOr add default_query_exec_mode=simple_protocol to the URL. On the direct URL the default cache mode is fine.
Migrations
golang-migrate, goose, atlas, and friends should use DATABASE_DIRECT_URL - they rely on advisory locks and DDL transactions.
Pitfalls
prepared statement "stmtcache_..." already exists- you are using the default exec mode through the pooler; see above.MaxConnsper instance: with multiple replicas, total client connections = replicas × MaxConns. Keep that under the plan budget or stay on the pooled URL.LISTEN/NOTIFYrequires the direct URL.
Laravel
Connect Laravel to a CapyDB Postgres database: pgsql driver settings in .env, sslmode in config/database.php, and the direct port for php artisan migrate.
SQLAlchemy
Connect SQLAlchemy 2.x to a CapyDB Postgres database: the postgresql+psycopg URL, an engine on the pooled endpoint, and Alembic migrations on the direct URL.