postgresql
Use when using PostgreSQL for application data or personal tooling — running a user-level instance without root (initdb and pg_ctl on a private port, listening on localhost only), schema migrations, c
Files1
View on GitHubSKILL.mdskills/tech/postgresql/SKILL.md
GitHubPostgreSQL
Default: a current major version, schema changes as ordered SQL migrations in git, constraints in the database (not only in code), connections over a local socket or localhost, pg_dump backups on a schedule.
A user-level instance (no root)
When a tool needs its own database on a workstation:
initdb -D "$DATA" --auth=scram-sha-256 --pwfile=<(printf '%s' "$PGPASS_INIT") -U app
pg_ctl -D "$DATA" -o "-p 55432 -c listen_addresses=localhost" -l "$DATA/server.log" start
createdb -p 55432 -U app appdb
- Pick an unusual port to avoid clashing with a system instance.
- Listen on
localhostonly; nothing on the network should reach it. - Let the tool start the server if it is not running (check with
pg_isready -p 55432), so users never manage it by hand. - Binaries can be unpacked from distribution packages into a user directory when installing system-wide is not possible.
Schema
- Primary keys (
bigint generated always as identityor UUIDs),NOT NULLby default,CHECKconstraints for valid ranges, foreign keys with deliberateON DELETEbehaviour,UNIQUEfor natural keys. timestamptzfor times;numericor integer minor units for money;textovervarchar(n)unless a limit is a rule.- Migrations are forward-only files (
0001_init.sql,0002_add_index.sql) applied in a transaction and recorded in a table.
Queries
- Upsert with
INSERT ... ON CONFLICT (key) DO UPDATE SET ...— atomic, no read-then-write race. - Always use parameters (
$1, driver placeholders); never format SQL strings with user input. EXPLAIN (ANALYZE, BUFFERS)before adding indexes; index the columns inWHERE,JOINandORDER BYof frequent queries; check that the plan uses them.- Large deletes and updates in batches to avoid long locks.
Backups
pg_dump -Fc appdb > backup.dumpregularly; test restores withpg_restoreinto a scratch database — an untested backup is a hope.
Verification loop
- Apply all migrations to an empty database; the app's tests pass against it.
- Constraint tests: inserting invalid rows fails.
EXPLAIN ANALYZEof the top queries shows index use and acceptable times.- Restore the latest backup successfully.
Pitfalls
timestampwithout time zone stores wall-clock times that drift across zones; usetimestamptz.- Connection storms from short-lived processes; reuse connections or add a pooler.
- Long transactions block vacuum and hold locks; keep them short.
- Implicit casts (comparing
textto numbers) prevent index use. - Major upgrades need
pg_upgradeor dump/restore; the data directory is not forward-compatible.