Database (pgx)
pkg/db/drivers/pgx manages a PostgreSQL connection pool using jackc/pgx.
lakta.NewRuntime( config.NewModule( config.WithConfigDirs(".", "./config"), config.WithArgs(os.Args[1:]), ), tint.NewModule(), slog.NewModule(), pgx.NewModule(), myapp.NewModule(),)Consuming the connection
Section titled “Consuming the connection”func (m *MyModule) Init(ctx context.Context) error { pool := do.MustInvoke[*pgxpool.Pool](lakta.GetInjector(ctx)) m.pool = pool return nil}Multi-instance
Section titled “Multi-instance”pgx.NewModule(pgx.WithName("primary")),pgx.NewModule(pgx.WithName("replica")),modules: db: pgx: primary: dsn: "postgres://user:pass@primary:5432/mydb" replica: dsn: "postgres://user:pass@replica:5432/mydb"Migrations
Section titled “Migrations”Schema migrations are driven by pressly/goose v3. Embed the .sql files and pass the filesystem with WithMigrations:
//go:embed migrations/*.sqlvar migrationsFS embed.FS
pgx.NewModule(pgx.WithMigrations(migrationsFS)),By default migrations do not run at startup. Enable the dev-time on-start path with config or pgx.WithMigrationsRunOnStart(true):
modules: db: pgx: default: dsn: "postgres://user:pass@localhost:5432/mydb" migrations: run_on_start: false # apply pending migrations during StartAsync table: "schema_migrations" # goose history table dir: "migrations" # sub-path within the embedded FS lock: "advisory" # "advisory" (replica-safe) or "none" allow_missing: false # apply out-of-order migrationsFor production, apply migrations out-of-band (e.g. an init container or a migrate subcommand) via RunMigrations, which opens its own pool and runs goose Up:
if err := pgx.RunMigrations(ctx, &cfg, migrationsFS); err != nil { return err}The advisory lock lets concurrent on-start runs across replicas serialize on a Postgres session advisory lock so each migration applies exactly once. Migrations containing non-transactional DDL (e.g. CREATE INDEX CONCURRENTLY) should use RunMigrations rather than run_on_start.
Transactions
Section titled “Transactions”Q(ctx) returns a Querier — the active transaction when one is live in ctx, otherwise the pool. Repos call it without knowing whether they run inside a transaction:
func (r *Repo) Insert(ctx context.Context, name string) error { _, err := pgx.Q(ctx).Exec(ctx, "INSERT INTO users (name) VALUES ($1)", name) return err}WithTx runs a function inside a transaction, committing on success and rolling back on error (or panic):
err := pgx.WithTx(ctx, func(ctx context.Context) error { if err := repo.Insert(ctx, "alice"); err != nil { return err // rolls back } return repo.Insert(ctx, "bob")}, pgx.WithIsolation(pgx.Serializable), pgx.WithReadOnly())Nesting WithTx inside a live transaction runs the inner scope in a SAVEPOINT; WithNewTx forces a fresh top-level transaction on the pool instead. QNamed(ctx, name) resolves a named instance.
Each transaction carries a done flag: once it commits or rolls back, Q(ctx) falls back to the pool rather than handing out the finished transaction. This guards against a goroutine detached inside WithTx (which copies the context values under context.WithoutCancel) accidentally using a completed transaction — a spawned goroutine correctly gets the pool, never the dead transaction.
Configuration Reference
Section titled “Configuration Reference”Config path: modules.db.pgx.<name>
dsnrequiredDSN is the database connection string used to configure the database connection
LAKTA_MODULES__DB__PGX__<NAME>__DSNmax_open_connsmaxOpenConns specifies the maximum number of open connections to the database. It maps to the "max_open_conns" configuration
LAKTA_MODULES__DB__PGX__<NAME>__MAX_OPEN_CONNSlog_levellogLevel specifies the logging level for database operations, supporting values like trace, debug, info, warn, error, none
LAKTA_MODULES__DB__PGX__<NAME>__LOG_LEVELhealth_checkhealthCheck enables or disables the database health check mechanism
LAKTA_MODULES__DB__PGX__<NAME>__HEALTH_CHECKmin_connsminConns is the minimum number of idle connections kept in the pool
LAKTA_MODULES__DB__PGX__<NAME>__MIN_CONNSmax_conn_lifetimemaxConnLifetime is the maximum age of a connection before it is closed
LAKTA_MODULES__DB__PGX__<NAME>__MAX_CONN_LIFETIMEmax_conn_idle_timemaxConnIdleTime is the maximum idle time before a connection is closed
LAKTA_MODULES__DB__PGX__<NAME>__MAX_CONN_IDLE_TIMEhealth_check_periodhealthCheckPeriod is how often the pool checks idle connection health
LAKTA_MODULES__DB__PGX__<NAME>__HEALTH_CHECK_PERIODstatement_timeoutstatementTimeout sets the per-statement timeout (Postgres statement_timeout). Zero disables it
LAKTA_MODULES__DB__PGX__<NAME>__STATEMENT_TIMEOUTmigrationsmigrations configures goose-driven schema migrations for this instancemigrations.run_on_startrunOnStart applies pending migrations during StartAsync. Default false —
LAKTA_MODULES__DB__PGX__<NAME>__MIGRATIONS__RUN_ON_STARTmigrations.tabletable is the migration history table name
LAKTA_MODULES__DB__PGX__<NAME>__MIGRATIONS__TABLEmigrations.dirdir is the sub-path within the embedded FS that holds the .sql files
LAKTA_MODULES__DB__PGX__<NAME>__MIGRATIONS__DIRmigrations.locklock selects the on-start locking strategy: "advisory" uses a Postgres
LAKTA_MODULES__DB__PGX__<NAME>__MIGRATIONS__LOCKmigrations.allow_missingallowMissing applies out-of-order (missing) migrations instead of erroring
LAKTA_MODULES__DB__PGX__<NAME>__MIGRATIONS__ALLOW_MISSING