When to Use
Use this skill when:
- Writing raw SQL queries for PostgreSQL
- Designing database schemas and tables
- Creating or optimizing indexes
- Working with JSONB, arrays, or composite types
- Implementing full-text search (tsvector/tsquery)
- Using PostgreSQL extensions (pg_trgm, uuid-ossp, etc.)
- Performance tuning and query optimization
- Writing stored procedures/functions
- Working with CTEs, window functions, or recursive queries
- Implementing constraints, triggers, or rules
Detailed References
- Data Types Reference — All PostgreSQL types (numeric, text, date, UUID, JSONB, arrays, enum, composite, range)
- Indexing Strategies — B-Tree, GIN, GiST, BRIN, Hash indexes
- Advanced Queries — Full-text search, CTEs, window functions, UPSERT, LATERAL, GROUPING SETS
- Performance & Schema Design — EXPLAIN, optimization, extensions, partitioning, constraints
Decision Trees
Choosing Data Types
Storing identifiers?
├─ Distributed system → UUID
├─ Single database, high volume → BIGSERIAL
└─ Single database, moderate → SERIAL/INTEGER
Storing text?
├─ Need case-insensitive → CITEXT (with extension)
├─ Fixed max length required → VARCHAR(n)
└─ Variable/unlimited → TEXT
Storing numbers?
├─ Money/financial → NUMERIC(precision, scale)
├─ Counts/IDs → INTEGER or BIGINT
└─ Scientific/approximate → DOUBLE PRECISION
Storing dates?
├─ Date only → DATE
├─ Time only → TIME
└─ Date + time → TIMESTAMPTZ (always with timezone!)
Storing structured data?
├─ Schema-less, queryable → JSONB
├─ List of values → ARRAY
├─ Fixed structure → Composite type or separate table
└─ Key-value pairs → JSONB or hstore
Choosing Index Type
Query pattern?
├─ Equality (=) only → HASH (or B-tree)
├─ Range (<, >, BETWEEN) → B-tree
├─ Pattern matching (LIKE '%x%') → GIN with pg_trgm
├─ Full-text search → GIN (faster) or GiST (smaller)
├─ JSONB containment (@>) → GIN
├─ Array operations (@>, &&) → GIN
├─ Geometric/range → GiST
└─ Time-series (ordered inserts) → BRIN
Table size?
├─ Small (< 100K rows) → B-tree usually sufficient
├─ Medium (100K-10M) → Consider partial indexes
└─ Large (> 10M) → Consider partitioning + BRIN
Aurora/Sequelize Integration
DataTypes Mapping
// In Aurora/Sequelize models
import { DataTypes } from 'sequelize';
// UUID
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
// JSONB
type: DataTypes.JSONB,
defaultValue: {}
// Array
type: DataTypes.ARRAY(DataTypes.STRING(64))
type: DataTypes.ARRAY(DataTypes.UUID)
type: DataTypes.ARRAY(DataTypes.INTEGER)
// Enum
type: DataTypes.ENUM('PENDING', 'ACTIVE', 'COMPLETED')
// Numeric
type: DataTypes.DECIMAL(10, 2)
type: DataTypes.BIGINT
type: DataTypes.INTEGER
// Text
type: DataTypes.TEXT
type: DataTypes.STRING(255)
// Date/Time
type: DataTypes.DATE // TIMESTAMP WITH TIME ZONE
type: DataTypes.DATEONLY // DATE
// Boolean
type: DataTypes.BOOLEAN
Index Definition in Models
@Table({
modelName: 'MyModel',
indexes: [
{ fields: ['email'], unique: true },
{ fields: ['tags'], using: 'GIN' },
{ fields: ['metadata'], using: 'GIN' },
{ fields: ['status'], where: { deletedAt: null } },
{ fields: ['tenantId', 'code'], unique: true },
],
})
Commands Reference
# Connect to database
psql -h localhost -U postgres -d database_name
# Execute SQL file
psql -h localhost -U postgres -d database_name -f script.sql
# Dump database
pg_dump -h localhost -U postgres database_name > backup.sql
pg_dump -h localhost -U postgres -Fc database_name > backup.dump
# Restore database
psql -h localhost -U postgres -d database_name < backup.sql
pg_restore -h localhost -U postgres -d database_name backup.dump
# Check PostgreSQL version
psql -c "SELECT version();"
# Show running queries
psql -c "SELECT pid, now() - pg_stat_activity.query_start AS duration, query FROM pg_stat_activity WHERE state = 'active';"
# Kill query
psql -c "SELECT pg_cancel_backend(pid);" -- Graceful
psql -c "SELECT pg_terminate_backend(pid);" -- Force
Resources
- Templates: See assets/ for SQL templates
- Aurora Criteria: See
aurora-criteria skill for QueryStatement patterns
- Aurora Models: See
src/@app/*/infrastructure/sequelize/*.model.ts for examples
1---2name: postgresql-23description: PostgreSQL expert skill - Advanced SQL, extensions, data types, indexing, performance tuning, and PostgreSQL-specific features. Trigger: When writing SQL queries, designing schemas, optimizing performance, using PostgreSQL extensions, or working with advanced data types.4license: MIT5---6
7## When to Use
8
9Use this skill when:
10- Writing raw SQL queries for PostgreSQL
11- Designing database schemas and tables
12- Creating or optimizing indexes
13- Working with JSONB, arrays, or composite types
14- Implementing full-text search (tsvector/tsquery)
15- Using PostgreSQL extensions (pg_trgm, uuid-ossp, etc.)
16- Performance tuning and query optimization
17- Writing stored procedures/functions
18- Working with CTEs, window functions, or recursive queries
19- Implementing constraints, triggers, or rules
20
21## Detailed References
22
23- [Data Types Reference](data-types.md) — All PostgreSQL types (numeric, text, date, UUID, JSONB, arrays, enum, composite, range)
24- [Indexing Strategies](indexing.md) — B-Tree, GIN, GiST, BRIN, Hash indexes
25- [Advanced Queries](queries.md) — Full-text search, CTEs, window functions, UPSERT, LATERAL, GROUPING SETS
26- [Performance & Schema Design](performance.md) — EXPLAIN, optimization, extensions, partitioning, constraints
27
28## Decision Trees
29
30### Choosing Data Types
31
32```
33Storing identifiers?
34├─ Distributed system → UUID
35├─ Single database, high volume → BIGSERIAL
36└─ Single database, moderate → SERIAL/INTEGER
37
38Storing text?
39├─ Need case-insensitive → CITEXT (with extension)
40├─ Fixed max length required → VARCHAR(n)
41└─ Variable/unlimited → TEXT
42
43Storing numbers?
44├─ Money/financial → NUMERIC(precision, scale)
45├─ Counts/IDs → INTEGER or BIGINT
46└─ Scientific/approximate → DOUBLE PRECISION
47
48Storing dates?
49├─ Date only → DATE
50├─ Time only → TIME
51└─ Date + time → TIMESTAMPTZ (always with timezone!)
52
53Storing structured data?
54├─ Schema-less, queryable → JSONB
55├─ List of values → ARRAY
56├─ Fixed structure → Composite type or separate table
57└─ Key-value pairs → JSONB or hstore
58```
59
60### Choosing Index Type
61
62```
63Query pattern?
64├─ Equality (=) only → HASH (or B-tree)
65├─ Range (<, >, BETWEEN) → B-tree
66├─ Pattern matching (LIKE '%x%') → GIN with pg_trgm
67├─ Full-text search → GIN (faster) or GiST (smaller)
68├─ JSONB containment (@>) → GIN
69├─ Array operations (@>, &&) → GIN
70├─ Geometric/range → GiST
71└─ Time-series (ordered inserts) → BRIN
72
73Table size?
74├─ Small (< 100K rows) → B-tree usually sufficient
75├─ Medium (100K-10M) → Consider partial indexes
76└─ Large (> 10M) → Consider partitioning + BRIN
77```
78
79## Aurora/Sequelize Integration
80
81### DataTypes Mapping
82
83```typescript
84// In Aurora/Sequelize models
85import { DataTypes } from 'sequelize';
86
87// UUID
88type: DataTypes.UUID,
89defaultValue: DataTypes.UUIDV4
90
91// JSONB
92type: DataTypes.JSONB,
93defaultValue: {}
94
95// Array
96type: DataTypes.ARRAY(DataTypes.STRING(64))
97type: DataTypes.ARRAY(DataTypes.UUID)
98type: DataTypes.ARRAY(DataTypes.INTEGER)
99
100// Enum
101type: DataTypes.ENUM('PENDING', 'ACTIVE', 'COMPLETED')
102
103// Numeric
104type: DataTypes.DECIMAL(10, 2)
105type: DataTypes.BIGINT
106type: DataTypes.INTEGER
107
108// Text
109type: DataTypes.TEXT
110type: DataTypes.STRING(255)
111
112// Date/Time
113type: DataTypes.DATE // TIMESTAMP WITH TIME ZONE
114type: DataTypes.DATEONLY // DATE
115
116// Boolean
117type: DataTypes.BOOLEAN
118```
119
120### Index Definition in Models
121
122```typescript
123@Table({
124 modelName: 'MyModel',
125 indexes: [
126 { fields: ['email'], unique: true },
127 { fields: ['tags'], using: 'GIN' },
128 { fields: ['metadata'], using: 'GIN' },
129 { fields: ['status'], where: { deletedAt: null } },
130 { fields: ['tenantId', 'code'], unique: true },
131 ],
132})
133```
134
135## Commands Reference
136
137```bash
138# Connect to database
139psql -h localhost -U postgres -d database_name
140
141# Execute SQL file
142psql -h localhost -U postgres -d database_name -f script.sql
143
144# Dump database
145pg_dump -h localhost -U postgres database_name > backup.sql
146pg_dump -h localhost -U postgres -Fc database_name > backup.dump
147
148# Restore database
149psql -h localhost -U postgres -d database_name < backup.sql
150pg_restore -h localhost -U postgres -d database_name backup.dump
151
152# Check PostgreSQL version
153psql -c "SELECT version();"
154
155# Show running queries
156psql -c "SELECT pid, now() - pg_stat_activity.query_start AS duration, query FROM pg_stat_activity WHERE state = 'active';"
157
158# Kill query
159psql -c "SELECT pg_cancel_backend(pid);" -- Graceful
160psql -c "SELECT pg_terminate_backend(pid);" -- Force
161```
162
163## Resources
164
165- **Templates**: See [assets/](assets/) for SQL templates
166- **Aurora Criteria**: See `aurora-criteria` skill for QueryStatement patterns
167- **Aurora Models**: See `src/@app/*/infrastructure/sequelize/*.model.ts` for examples