| name | postgres |
| version | 1.0.0 |
| description | PostgreSQL queries, schema management, backups, and performance tuning. |
| author | ZeptoClaw |
| license | MIT |
| tags | ["database","postgresql","sql"] |
| env_needed | [{"name":"DATABASE_URL","description":"PostgreSQL connection string (postgresql://user:pass@host:5432/db)","required":false}] |
| metadata | {"zeptoclaw":{"emoji":"🐘","requires":{"anyBins":["psql","pg_dump"]}}} |
PostgreSQL Skill
Interact with PostgreSQL databases — queries, schema changes, backups, and diagnostics.
Connect
psql "$DATABASE_URL"
psql -h localhost -U myuser -d mydb -p 5432
Common Queries
\dt
\d users
SELECT schemaname, tablename, n_live_tup AS rows
FROM pg_stat_user_tables ORDER BY n_live_tup DESC;
SELECT query, calls, mean_exec_time::int AS avg_ms, total_exec_time::int AS total_ms
FROM pg_stat_statements ORDER BY mean_exec_time DESC LIMIT 10;
Schema Management
psql "$DATABASE_URL" -f migration.sql
psql "$DATABASE_URL" -c "
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
customer_id INTEGER NOT NULL REFERENCES customers(id),
total NUMERIC(10,2) NOT NULL,
status TEXT DEFAULT 'pending',
created_at TIMESTAMPTZ DEFAULT NOW()
);"
psql "$DATABASE_URL" -c "ALTER TABLE orders ADD COLUMN notes TEXT;"
psql "$DATABASE_URL" -c "CREATE INDEX CONCURRENTLY idx_orders_customer ON orders(customer_id);"
Backup & Restore
pg_dump "$DATABASE_URL" -Fc -f backup_$(date +%Y%m%d).dump
pg_restore -d "$DATABASE_URL" --no-owner -1 backup_20260101.dump
pg_dump "$DATABASE_URL" --schema-only -f schema.sql
pg_dump "$DATABASE_URL" -t orders -f orders.sql
Performance Diagnostics
SELECT pid, usename, application_name, state, query_start, query
FROM pg_stat_activity WHERE state != 'idle';
SELECT tablename, pg_size_pretty(pg_total_relation_size(tablename::text)) AS size
FROM pg_tables WHERE schemaname = 'public' ORDER BY pg_total_relation_size(tablename::text) DESC;
SELECT schemaname, tablename, seq_scan, idx_scan,
seq_scan - idx_scan AS seq_minus_idx
FROM pg_stat_user_tables WHERE seq_scan > 0
ORDER BY seq_scan DESC LIMIT 20;
SELECT pg_terminate_backend(pid) FROM pg_stat_activity
WHERE pid != pg_backend_pid() AND query_start < NOW() - INTERVAL '5 minutes';
Tips
- Use
CONCURRENTLY for CREATE INDEX in production — avoids table lock
- Always test
ALTER TABLE on a staging db first
pg_dump -Fc (custom format) is smaller and restores faster than plain SQL
- Set
statement_timeout = '30s' in postgresql.conf to prevent runaway queries