Postgres
Use for PostgreSQL regardless of ORM — schema design, queries, indexing, EXPLAIN/plans, JSONB, partitions, extensions, migrations, security. Triggers — psql, SQL DDL on a Postgres stack.From its SKILL.md
npx -y skills add muxammadmamajonov/dot-claude --skill postgresAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
7.0 KB, ~1.7k tokens by cl100k_base, as published. Nobody here has run it
PostgreSQL Development
When to use
- Designing or reviewing table schemas, constraints, and indexes
- Writing or optimising complex SQL queries, CTEs, or window functions
- Authoring or debugging database migrations
- Configuring connection pooling, vacuuming, replication, or backups
- Diagnosing slow queries with
EXPLAIN (ANALYZE, BUFFERS) - Implementing row-level security, roles, or audit logging
Workflow
- Understand the access patterns first — what queries will run most frequently and at what volume? Schema design follows query design, not the reverse.
- Design the schema:
- Choose the correct data types (avoid
TEXTwhereVARCHAR(n)or a domain type is better; useTIMESTAMPTZnotTIMESTAMP; useUUIDorBIGSERIALfor PKs). - Add constraints early:
NOT NULL,UNIQUE,CHECK, foreign keys withON DELETEpolicy. - Normalise to 3NF by default; denormalise only when a proven performance need exists with a comment explaining why.
- Choose the correct data types (avoid
- Create indexes deliberately:
- Single-column B-tree for equality and range filters on high-cardinality columns.
- Composite index column order: most selective equality columns first, then range columns.
- Partial indexes for sparse conditions:
CREATE INDEX ON orders (user_id) WHERE status = 'pending'. - GIN for
jsonb, full-text search, and array containment.
- Write the migration:
- One migration file per logical change with an
upanddown(or an explicit comment if rollback is destructive). - Never add a
NOT NULLcolumn without aDEFAULTin the same statement on a live table — it rewrites the full table pre-PG11. - Add indexes
CONCURRENTLYon production tables to avoid locking.
- One migration file per logical change with an
- Write queries:
- Parameterise all user input — never string-interpolate into SQL.
- Use CTEs for readability; materialise with
MATERIALIZEDonly when the planner is misestimating. - Prefer
JOINover correlated subqueries inSELECTlist.
- Profile slow queries:
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)on the exact query with real parameters.- Look for:
Seq Scanon large tables, highRows Removed by Filter,Hash Batches > 1(spill to disk), nested loops with large outer sets. - Run
pg_stat_statementsto find top-N slow queries by total time.
- Audit for security — see .claude/checklists/security.md. Row-level security, principle of least privilege on roles, encrypted connections.
- Verify backup/restore before going live — a backup that has never been restored is an untested backup.
Standards
Schema design
- Primary keys:
BIGSERIALfor append-heavy tables;UUID(gen_random_uuid()) for distributed or externally referenced entities. - Always
TIMESTAMPTZfor timestamps — store in UTC, display in application layer. - Foreign keys must have an index on the referencing column unless they are almost never queried by FK.
- Use
ENUMtypes or a lookup table for finite, stable sets of values; useCHECK (status IN (...))for small, unlikely-to-change sets.
Migrations
- Migrations are immutable once merged — never edit a committed migration; write a new one.
- Test
upanddownmigrations in CI against a real Postgres container. - Large table changes (adding a column, changing a type): do in multiple small migrations with no-downtime patterns (expand/contract).
- Never
DROP TABLEorDROP COLUMNin the same deployment as the code that stops using it — wait one release.
Queries
- Use
RETURNINGto get generated IDs/timestamps in a single round trip instead of a follow-upSELECT. LIMIT+OFFSETpagination degrades at high offsets; use keyset pagination (WHERE id > $last_id ORDER BY id LIMIT $n).COUNT(*)is fast;COUNT(DISTINCT col)on large tables is slow — consider HyperLogLog viapg_hllfor approximations.- Wrap multi-step mutations in explicit transactions with appropriate isolation level (
READ COMMITTEDdefault;REPEATABLE READfor read-modify-write cycles).
Performance
autovacuummust be healthy: checkpg_stat_user_tables.n_dead_tup. Tuneautovacuum_vacuum_scale_factorfor large tables.- Connection pooling is mandatory at scale — use PgBouncer (transaction mode) or
pgpool-II; never open one Postgres connection per application thread. shared_buffers= 25% of RAM;effective_cache_size= 75% of RAM;work_mem= RAM / (max_connections × 2) as a starting point.
Security
- Application user has
SELECT,INSERT,UPDATE,DELETEon required tables only — neverSUPERUSERor schema-owner. - Enable
ssl = on; requirehostsslinpg_hba.conf. - Never store plain-text passwords; store argon2/bcrypt hashes.
- Use Row-Level Security (
ALTER TABLE ... ENABLE ROW LEVEL SECURITY) for multi-tenant data.
Do not
- Do not use
SELECT *in application queries — always list columns explicitly. - Do not run
VACUUM FULLorREINDEXwithout a maintenance window — they takeAccessExclusiveLock. - Do not create indexes without profiling first — every index slows writes.
- Do not use
serial/bigserialfor new projects — useGENERATED ALWAYS AS IDENTITY(SQL standard). - Do not share a database superuser account in application connection strings.
Common mistakes to avoid
| Mistake | Fix |
|---|---|
Adding a NOT NULL column to a large live table | Use ADD COLUMN col TYPE DEFAULT val, then backfill, then add NOT NULL in a later migration (PG<11). PG11+ handles this in one DDL. |
| Index not used despite existing | Check column order, data type mismatch, or function wrapping in WHERE clause (WHERE lower(email) = ? needs functional index). |
LIKE '%term%' not using index | Use pg_trgm GIN index: CREATE INDEX ON t USING gin (col gin_trgm_ops). |
| Long-running transaction blocking autovacuum | Set statement_timeout and idle_in_transaction_session_timeout in postgresql.conf. |
| JSONB overuse replacing relational columns | Use JSONB for truly variable/schemaless attributes; model known fields as typed columns. |
Missing FOR UPDATE in optimistic lock patterns | Use SELECT ... FOR UPDATE or UPDATE ... WHERE version = $v with row count check. |
Output format
- Schema change:
CREATE TABLEorALTER TABLEDDL with all constraints, followed byCREATE INDEXstatements. - Migration file: numbered file (
YYYYMMDDHHMMSS_description.sql) with-- migrate:upand-- migrate:downsections. - Query optimisation: original query,
EXPLAIN ANALYZEsnippet of the problem node, rewritten query, and expected improvement. - Role/permission setup:
CREATE ROLE,GRANT,REVOKEstatements with comments on why each privilege is granted.
Related checklists
- .claude/checklists/security.md
- .claude/checklists/performance.md
- .claude/checklists/qa.md
Related agents
- .claude/agents/core/orchestrator.md
- .claude/agents/engineering/database-architect.md
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.