Postgresql best practices
Skill ulpi-io/plugin-marketplace/plugins/mindrally/skills/postgresql-best-practices
PostgreSQL 18+ comprehensive best practices for enterprise database development. Provides schema architecture patterns, Table API design, PL/pgSQL coding standards, migrations, and data warehousing. USE THIS SKILL WHEN THE USER: - Creates PostgreSQL schemas, tables, functions, procedures, or triggers - Asks about PostgreSQL data types (uuid, text, timestamptz, jsonb, numeric) - Writes PL/pgSQL code and needs naming conventions (l_, in_, io_, co_ prefixes) - Implements Table API pattern (SECURITY DEFINER functions, schema separation) - Sets up database migrations or schema versioning - Needs index optimization, constraint design, or query performance help - Asks about PostgreSQL 18+ features (uuidv7, virtual columns, temporal constraints) - Builds data warehouses with Medallion Architecture (Bronze/Silver/Gold) - Needs data lineage tracking, ETL patterns, or audit logging - Reviews database code for best practices or anti-patterns - Migrates from Oracle PL/SQL to PostgreSQL PL/pgSQL - Sets up CI/CD pipelines for database changes CORE PATTERNS: - Three-schema separation: data (tables) → private (internal) → api (external) - Table API: All access through SECURITY DEFINER functions with SET search_path - Native migration system: Pure PL/pgSQL alternative to Flyway/Liquibase - Trivadis naming: l_ (local), in_ (input), io_ (inout), co_ (constant)From its SKILL.md
npx -y skills add ulpi-io/plugin-marketplace --skill postgresql-best-practicesAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 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
13.1 KB, ~2.8k tokens by cl100k_base, as published. Nobody here has run it
PostgreSQL Advanced Best Practices (PostgreSQL 18+)
Architecture at a Glance
┌─── PostgreSQL Database ──────────────────────────────┐
│ │
│ ┌──────────────────┐ ┌───────────────────────┐ │
│ │ api schema │ │ private schema │ │
┌─────────────┐ │ │──────────────────│ │───────────────────────│ │
│ Application │─EXECUTE─▶│ get_customer() │───▶│ set_updated_at() │ │
└─────────────┘ │ │ insert_order() │ │ hash_password() │ │
│ │ └────────┬─────────┘ └──────────┬────────────┘ │
│ │ │ │ │
│ │ │ SECURITY DEFINER │ triggers │
│ │ ▼ ▼ │
│ │ ┌──────────────────────────────────────────────┐ │
│ │ │ data schema │ │
BLOCKED │ │──────────────────────────────────────────────│ │
│ │ │ customers orders ... │ │
└ ─ ─ ─ ✕ │ └──────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────┘
Skill Contents
🚀 Getting Started (Read These First)
| Document | Purpose |
|---|---|
| quick-reference.md | QUICK LOOKUP - Single-page cheat sheet (print this!) |
| schema-architecture.md | START HERE - Schema separation pattern (data/private/api) |
| coding-standards-trivadis.md | Coding standards & naming conventions (l_, g_, co_) |
📚 Core Reference (Use Daily)
| Document | Purpose |
|---|---|
| plpgsql-table-api.md | Table API functions, procedures, triggers |
| schema-naming.md | Naming conventions for all objects |
| data-types.md | Data type selection (UUIDv7, text, timestamptz) |
| indexes-constraints.md | Index types, strategies, constraints |
| migrations.md | Native migration system documentation |
| anti-patterns.md | Common mistakes to avoid |
| checklists-troubleshooting.md | Project checklists & problem solutions |
🔧 Advanced Topics (When Needed)
| Document | Purpose |
|---|---|
| testing-patterns.md | pgTAP unit testing, test factories |
| performance-tuning.md | EXPLAIN ANALYZE, query optimization, JIT |
| row-level-security.md | RLS patterns, multi-tenant isolation |
| jsonb-patterns.md | JSONB indexing, queries, validation |
| audit-logging.md | Generic audit triggers, change tracking |
| bulk-operations.md | COPY, batch inserts, upserts |
| session-management.md | Session variables, connection pooling |
| transaction-patterns.md | Isolation levels, locking, deadlock prevention |
| full-text-search.md | tsvector, tsquery, ranking, multi-language |
| partitioning.md | Range, list, hash partitioning strategies |
| window-functions.md | Frames, ranking, running calculations |
| time-series.md | Time-series data patterns, BRIN indexes |
| event-sourcing.md | Event store, projections, CQRS |
| queue-patterns.md | Job queues, SKIP LOCKED, LISTEN/NOTIFY |
| encryption.md | pgcrypto, column encryption, TLS |
| vector-search.md | pgvector, embeddings, similarity search |
| postgis-patterns.md | Spatial data, geographic queries |
🚀 DevOps & Migration
| Document | Purpose |
|---|---|
| oracle-migration-guide.md | PL/SQL to PL/pgSQL conversion |
| cicd-integration.md | GitHub Actions, GitLab CI, Docker |
| monitoring-observability.md | pg_stat_statements, metrics, alerting |
| backup-recovery.md | pg_dump, pg_basebackup, PITR |
| replication-ha.md | Streaming/logical replication, failover |
📊 Data Warehousing
| Document | Purpose |
|---|---|
| data-warehousing-medallion.md | Medallion Architecture - Bronze/Silver/Gold, data lineage, ETL |
| analytical-queries.md | Analytical query patterns, OLAP optimization, GROUPING SETS |
Executable Scripts
| Script | Purpose |
|---|---|
| 001_install_migration_system.sql | Install migration system (core functions) |
| 002_migration_runner_helpers.sql | Helper procedures (run_versioned, run_repeatable) |
| 003_example_migrations.sql | Example migration patterns |
| 999_uninstall_migration_system.sql | Clean removal of migration system |
Core Architecture
Schema Separation Pattern
Application → api schema → data schema
↓
private schema (triggers, helpers)
| Schema | Contains | Access | Purpose |
|---|---|---|---|
data | Tables, indexes | None | Data storage |
private | Triggers, helpers | None | Internal logic |
api | Functions, procedures | Applications | External interface |
app_audit | Audit tables | Admins | Change tracking |
app_migration | Migration tracking | Admins | Schema versioning |
Security Model
All api functions MUST have:
SECURITY DEFINER
SET search_path = data, private, pg_temp
Quick Reference
Create Table Pattern
CREATE TABLE data.{table_name} (
id uuid PRIMARY KEY DEFAULT uuidv7(),
-- columns...
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE TRIGGER {table}_bu_updated_trg
BEFORE UPDATE ON data.{table_name}
FOR EACH ROW EXECUTE FUNCTION private.set_updated_at();
API Function Pattern
CREATE FUNCTION api.{action}_{entity}(in_param type)
RETURNS TABLE (col1 type, col2 type)
LANGUAGE sql STABLE
SECURITY DEFINER
SET search_path = data, private, pg_temp
AS $$
SELECT col1, col2 FROM data.{table} WHERE ...;
$$;
API Procedure Pattern
CREATE PROCEDURE api.{action}_{entity}(
in_param type,
INOUT io_id uuid DEFAULT NULL
)
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = data, private, pg_temp
AS $$
BEGIN
INSERT INTO data.{table} (...) VALUES (...) RETURNING id INTO io_id;
END;
$$;
Migration Pattern
SELECT app_migration.acquire_lock();
CALL app_migration.run_versioned(
in_version := '001',
in_description := 'Description',
in_sql := $mig$ ... $mig$,
in_rollback_sql := '...'
);
SELECT app_migration.release_lock();
Naming Conventions
Trivadis-Style Variable Prefixes
| Prefix | Type | Example |
|---|---|---|
l_ | Local variable | l_customer_count |
g_ | Session/global variable | g_current_user_id |
co_ | Constant | co_max_retries |
in_ | IN parameter | in_customer_id |
out_ | OUT parameter (functions only) | out_total |
io_ | INOUT parameter (procedures) | io_id |
c_ | Cursor | c_active_orders |
r_ | Record | r_customer |
t_ | Array/table | t_order_ids |
e_ | Exception | e_not_found |
Note: PostgreSQL procedures only support INOUT parameters, not OUT. Use
io_prefix for all procedure output parameters.
Database Objects
| Object | Pattern | Example |
|---|---|---|
| Table | snake_case, plural | orders, order_items |
| Column | snake_case | customer_id, created_at |
| Primary Key | id | id |
| Foreign Key | {table_singular}_id | customer_id |
| Index | {table}_{cols}_idx | orders_customer_id_idx |
| Unique | {table}_{cols}_key | users_email_key |
| Function | {action}_{entity} | get_customer, select_orders |
| Procedure | {action}_{entity} | insert_order, update_status |
| Trigger | {table}_{timing}{event}_trg | orders_bu_trg |
Data Type Recommendations
| Use | Instead Of |
|---|---|
text | char(n), varchar(n) |
numeric(p,s) | money, float |
timestamptz | timestamp |
boolean | integer flags |
uuidv7() | serial, uuid_generate_v4() |
GENERATED ALWAYS AS IDENTITY | serial, bigserial |
jsonb | json, EAV pattern |
Critical Anti-Patterns
- ❌ Direct table access from applications
- ❌
RETURNS SETOF table(exposes all columns) - ❌ Missing
SET search_pathwithSECURITY DEFINER - ❌
timestampwithout timezone - ❌
NOT INwith subqueries (useNOT EXISTS) - ❌
BETWEENwith timestamps (use>= AND <) - ❌ Missing indexes on foreign keys
- ❌
serial/bigserial(useIDENTITY) - ❌
varchar(n)arbitrary limits (usetext) - ❌
SELECT FOR UPDATEwithoutNOWAIT/SKIP LOCKED
PostgreSQL 18+ Features
| Feature | Usage |
|---|---|
uuidv7() | id uuid DEFAULT uuidv7() - timestamp-ordered UUIDs |
| Virtual generated columns | col type GENERATED ALWAYS AS (expr) - computed at query time |
OLD/NEW in RETURNING | UPDATE ... RETURNING OLD.col, NEW.col |
| Temporal constraints | PRIMARY KEY (id) WITHOUT OVERLAPS |
NOT VALID constraints | Add constraints without full table scan |
File Organization
db/
├── migrations/
│ ├── V001__create_schemas.sql
│ ├── V002__create_tables.sql
│ └── repeatable/
│ ├── R__private_triggers.sql
│ └── R__api_functions.sql
├── schemas/
│ ├── data/ # Table definitions
│ ├── private/ # Internal functions
│ └── api/ # External interface
└── seeds/ # Reference data
What ships with it: 98 files
1414.3 KB alongside SKILL.md, 3 of them executable
references/
- analytical-queries.md33.2 KB
- anti-patterns.md16.9 KB
- audit-logging.md22.0 KB
- backup-recovery.md19.3 KB
- bulk-operations.md18.0 KB
- checklists-troubleshooting.md4.0 KB
- cicd-integration.md20.7 KB
- coding-standards-trivadis.md35.8 KB
- data-types.md14.1 KB
- data-warehousing-medallion.md73.1 KB
- encryption.md15.8 KB
- event-sourcing.md19.7 KB
- full-text-search.md21.8 KB
- indexes-constraints.md18.7 KB
- jsonb-patterns.md33.5 KB
- migrations.md30.9 KB
- monitoring-observability.md27.3 KB
- oracle-migration-guide.md19.9 KB
- partitioning.md23.3 KB
- performance-tuning.md25.2 KB
- plpgsql-table-api.md21.5 KB
- postgis-patterns.md13.8 KB
- queue-patterns.md16.3 KB
- quick-reference.md8.2 KB
- replication-ha.md18.0 KB
- row-level-security.md21.1 KB
- schema-architecture.md17.0 KB
- schema-naming.md7.4 KB
- session-management.md18.8 KB
- testing-patterns.md26.0 KB
- time-series.md18.8 KB
- transaction-patterns.md17.3 KB
- vector-search.md18.1 KB
- window-functions.md13.1 KB
scripts/
58 more files not listed here. See all 98 in the repository.