PostgreSQL — MVCC, indexes, partitioning, JSONB, query tuning.
Scanned 9/5/2026
Install to Claude Code
npx -y skills add Dev-Toolbelt/dev-team-agents --skill postgres --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Postgres?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/dev-toolbelt-postgres)More formats (shields.io, HTML) on the badges page.
---
name: postgres
description: PostgreSQL — MVCC, indexes, partitioning, JSONB, query tuning.
---
# PostgreSQL Reference
## When to Load
Load when the project uses PostgreSQL (signal: `pg`, `psycopg2`, `postgres:` in docker-compose, `DATABASE_URL` with `postgres://`, `prisma` with `postgresql` provider).
## CLI Connection
```bash
psql "$DATABASE_URL"
# or with individual vars:
PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "${DB_PORT:-5432}" -U "$DB_USER" -d "$DB_NAME"
# Supabase local dev:
psql "postgresql://postgres:postgres@localhost:54322/postgres"
```
Key inspection commands:
```bash
psql -c "\d+ table_name" # table structure + storage info
psql -c "EXPLAIN (ANALYZE, BUFFERS) SELECT ..."
psql -c "SELECT * FROM pg_stat_user_tables ORDER BY n_dead_tup DESC;"
psql -c "SELECT * FROM pg_stat_activity WHERE state = 'active';"
```
## MVCC & Transaction Isolation
| Isolation level | Default | Prevents |
|-----------------|---------|---------|
| Read Committed | ✅ PostgreSQL default | Dirty reads |
| Repeatable Read | — | Non-repeatable reads |
| Serializable | — | Phantom reads |
- Row versions (tuples) are never overwritten; old versions cleaned by `VACUUM`
- Long-running transactions prevent VACUUM from reclaiming dead tuples → table bloat
- Monitor with: `SELECT relname, n_dead_tup FROM pg_stat_user_tables ORDER BY n_dead_tup DESC`
## Index Types
| Type | Use when |
|------|----------|
| B-tree (default) | Equality and range queries on orderable types |
| GIN | Full-text search; JSONB containment (`@>`); array overlap |
| GiST | Geometric types; range types; nearest-neighbour |
| BRIN | Append-only large tables with sequential correlation (e.g., time series) |
| Hash | Equality-only; rarely preferred over B-tree |
| Partial | Index a subset of rows: `CREATE INDEX ON orders(user_id) WHERE status = 'active'` |
## JSONB vs JSON
- Use `jsonb` (binary storage, indexable, operators) over `json` (text storage, preserved order)
- GIN index on `jsonb`: `CREATE INDEX ON table USING GIN (col)` for `@>` and `?` operators
- Avoid storing deeply nested structures; flatten frequently queried keys into columns
## Partitioning
| Type | Best for |
|------|----------|
| Range | Time series (partition by month/year) |
| List | Enum-like values (region, status) |
| Hash | Even distribution without natural range |
Use `pg_partman` for automated range partition creation. Always include the partition key in queries to enable partition pruning.
## CTEs and Query Planning
- CTEs are **optimization fences** in Postgres < 12; in >= 12, the planner inlines non-recursive CTEs by default
- Force inlining: `WITH MATERIALIZED` (>= 12) or `NOT MATERIALIZED`
- `EXPLAIN (ANALYZE, BUFFERS)` is mandatory before merging slow queries
- Key stats: `Seq Scan` on large tables, `Rows Removed by Filter`, high `Buffers hit/read` ratio
## Common Gotchas
| Gotcha | Fix |
|--------|-----|
| `LIKE '%term%'` can't use B-tree | Use `pg_trgm` extension + GIN index |
| `OFFSET n` scans all preceding rows | Use keyset pagination: `WHERE id > :last_id` |
| `COUNT(*)` is expensive on large tables | Use `pg_stat_user_tables.n_live_tup` for estimates |
| `CURRENT_TIMESTAMP` vs `NOW()` | Same within a transaction; `clock_timestamp()` changes mid-transaction |
| UUID as PK causes index fragmentation | Use `gen_random_uuid()` (UUIDv4) or UUIDv7 for sequential behaviour |
## Extensions Worth Knowing
| Extension | Purpose |
|-----------|---------|
| `pg_trgm` | Trigram similarity for fuzzy search and LIKE index |
| `pgcrypto` | `gen_random_uuid()`, encryption functions |
| `uuid-ossp` | Alternative UUID generation |
| `pg_stat_statements` | Track slow query statistics |
| `timescaledb` | Time-series optimizations |
| `PostGIS` | Spatial data and geospatial queries |
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!