Use for PostgreSQL 18 SQL, migrations, DDL, functions, RLS policies, indexes, query plans, extensions, and SQL embedded in TypeScript via @effect/sql-pg. Enforces set-algebraic queries, schema-level invariants, current PostgreSQL features, extension-first design, tenant security, observability, and migration safety.
Scanned 9/19/2026
Install to Claude Code
npx -y skills add bsamiee/Parametric_Portal --skill coding-pg --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Coding Pg?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/bsamiee-coding-pg)More formats (shields.io, HTML) on the badges page.
---
name: coding-pg
description: >-
Use for PostgreSQL 18 SQL, migrations, DDL, functions, RLS policies,
indexes, query plans, extensions, and SQL embedded in TypeScript via
@effect/sql-pg. Enforces set-algebraic queries, schema-level invariants,
current PostgreSQL features, extension-first design, tenant security,
observability, and migration safety.
---
# [H1][CODING-PG]
>**Dictum:** *PostgreSQL schema design, query algebra, and security posture govern all SQL work.*
All SQL follows five governing principles:
- **Polymorphic** — one function/query per concern, generic over specific via parameter dispatch and dynamic SQL
- **Set-algebraic** — express operations as set transformations; zero row-at-a-time iteration
- **Strongly typed** — domain types, composite types, range types; zero untyped `text` columns for structured data
- **Programmatic** — variable-driven predicates, parameterized DDL, zero stringly-typed identifiers
- **Declarative-first** — constraints, generated columns, and RLS policies enforce invariants at the schema level; application logic is last resort
- **Source-current** — PostgreSQL 18/current docs are the truth baseline; examples must state current semantics, not stale point-version folklore
## Paradigm
- **Immutability**: append-only event tables, temporal versioning via `tstzrange` + `WITHOUT OVERLAPS`, soft-delete via `archived_at` timestamp — zero in-place mutation of historical records
- **Type anchoring**: one `CREATE TYPE` or `CREATE DOMAIN` per semantic concept — derive column declarations from domain types, never redeclare equivalent `CHECK` constraints across tables
- **Expression control flow**: `CASE`-free query design via `COALESCE`, `NULLIF`, `GREATEST`/`LEAST`, lateral joins, and `FILTER (WHERE ...)` — reserve `CASE` for irreducible multi-branch projection only
- **Set composition**: CTEs as named relational algebra steps; `UNION ALL` over procedural accumulation; `MERGE` over conditional INSERT/UPDATE sequences
- **Constraint-driven integrity**: `CHECK`, `EXCLUDE`, `WITHOUT OVERLAPS`, `GENERATED ALWAYS AS` — push validation into DDL; application-layer checks are redundant defense, not primary enforcement
- **Extension-first**: pgvector for embeddings, pg_trgm for fuzzy search, PostGIS for spatial, TimescaleDB for time-series — never hand-roll what an extension provides
## Conventions
| Layer | Mechanism | Owns |
| -------------- | --------------------------------- | -------------------------------------------------------------- |
| Identity | `uuidv7()` | PK generation — timestamp-ordered, B-tree friendly |
| Temporal | `WITHOUT OVERLAPS` + `PERIOD` | Range integrity — temporal PKs, FKs, exclusion constraints |
| Projection | Virtual generated columns | Computed fields — zero storage, instant `ALTER TABLE` |
| Write strategy | `MERGE ... RETURNING OLD/NEW` | Upsert + audit trail in single statement |
| Type safety | Domain types + composite types | Semantic column typing — branded scalars, structured records |
| Search | GIN + pg_trgm / pgvector | Full-text, trigram similarity, vector nearest-neighbor |
| Partitioning | Declarative + pg_partman | Time/hash/list partitioning with automatic lifecycle |
| Scheduling | pg_cron | In-database job scheduling — maintenance, materialized views |
| Security | RLS + SECURITY INVOKER | Row-level tenant isolation, least-privilege function execution |
| Observability | pg_stat_statements + auto_explain | Query fingerprinting, automatic slow-query plan capture |
- Effect-SQL (`@effect/sql` + `@effect/sql-pg`) is the assumed TypeScript integration layer.
- `Model.Class` field modifiers (`Generated`, `FieldOnly`, `FieldExcept`, `Sensitive`) must align with DDL constraints — `Generated` fields map to `DEFAULT` or `GENERATED ALWAYS AS` columns.
- All SQL identifiers use `snake_case`; TypeScript receives `camelCase` via `transformResultNames`.
## Contracts
**Type discipline**
- One domain type per semantic concept; column declarations reference the domain, never inline `CHECK` constraints.
- Composite types for structured return values from functions — never `OUT` parameter proliferation.
- Range types (`tstzrange`, `int4range`, custom) for interval semantics — never dual `start`/`end` columns.
- `NOT NULL` is default posture; nullable columns require documented justification.
**Query algebra**
- CTEs for named intermediate results; recursive CTEs with `SEARCH BREADTH FIRST` or `CYCLE` for graph traversal.
- `MERGE` with `RETURNING OLD.*, NEW.*, merge_action()` for write-audit fusion.
- Window functions with `GROUPS`/`EXCLUDE` framing where row-count framing is insufficient.
- `JSON_TABLE` / `jsonb_path_query` for structured JSON extraction — never application-side JSON parsing of database-resident JSON.
- `LATERAL JOIN` for correlated subquery materialization — never scalar subqueries in SELECT list.
**Index strategy**
- Every `WHERE` clause pattern has a corresponding index; partial indexes for selective predicates.
- `INCLUDE` columns for index-only scans on high-frequency read paths.
- GIN for JSONB containment (`@>`), array overlap (`&&`), full-text (`@@`).
- GiST for range overlap, spatial queries, nearest-neighbor when combined with `ORDER BY <-> LIMIT`.
- BRIN for append-only monotonic columns (timestamps, serial IDs) — orders of magnitude smaller than B-tree.
**Security**
- RLS enabled on every tenant-scoped table; policies use fail-closed `nullif(current_setting('app.current_tenant', true), '')` tenant scoping.
- Functions default to `SECURITY INVOKER` (always the default); `SECURITY DEFINER` only with `SET search_path = pg_catalog, public`.
- Column-level `GRANT` for sensitive fields — never rely on view-based column hiding alone.
**Performance**
- `EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS)` is the verification tool; assertions against plan shape, not just row counts.
- AIO (`io_method = io_uring`) for sequential scan and vacuum workloads on Linux.
- Parallel query enabled for aggregation, hash join, index scan — `max_parallel_workers_per_gather` tuned to workload.
- `FOR UPDATE SKIP LOCKED` for concurrent batch processing — never `SELECT ... FOR UPDATE` without `SKIP LOCKED` on queue tables.
## Anti-Patterns
| Label | Symptom |
| ----------------------------- | ------------------------------------------------------------------------------ |
| STRING_TYPING | `text` for structured data (JSON, enum values, composite structures) |
| DUAL_COLUMN_RANGE | `start_date`/`end_date` instead of `tstzrange` with exclusion constraint |
| IMPERATIVE_BATCH | PL/pgSQL `LOOP` with row-at-a-time `UPDATE` instead of set-based `MERGE`/CTE |
| INDEX_SPRAWL | Redundant single-column indexes subsumed by existing composite indexes |
| NULLABLE_DEFAULT | Columns nullable without documented justification |
| TRIGGER_LOGIC | Business logic in triggers instead of `MERGE RETURNING` or generated columns |
| OFFSET_PAGINATION | `LIMIT/OFFSET` instead of keyset pagination for client-facing endpoints |
| SECURITY_DEFINER_LEAK | `SECURITY DEFINER` without `SET search_path` — search_path injection vector |
| STRINGLY_POLICY | RLS policy with hardcoded literals instead of `current_setting()` |
| FUNCTION_PROLIFERATION | Separate functions for each query variant instead of one polymorphic function |
| APPLICATION_SIDE_JSON | Fetching raw JSONB and parsing in application instead of `jsonb_path_query` |
| MANUAL_PARTITION | Hand-written partition creation instead of pg_partman lifecycle management |
| UNVALIDATED_CONSTRAINT | `ADD CONSTRAINT ... NOT VALID` without subsequent `VALIDATE CONSTRAINT` |
| IF_THEN_DISPATCH | PL/pgSQL `IF p_op = 'get' THEN ... ELSIF` instead of VALUES-based dynamic SQL |
| NONCOMPOSABLE_CAGG | `PERCENTILE_CONT` in hierarchical CAGG; non-composable across tiers |
| LEGACY_UUID | Non-ordered UUID generation on new ordered PKs where `uuidv7()` fits better |
| STALE_HEALTH_VIEW | Materialized views for real-time health monitoring instead of inline queries |
| EXCLUDE_OVER_WITHOUT_OVERLAPS | EXCLUDE instead of WITHOUT OVERLAPS PK/UNIQUE for temporal overlap in PG 18 |
| RAW_UUID_ID | Raw `S.UUID` for PK/FK instead of `S.UUID.pipe(S.brand('EntityId'))` |
| BARE_FOR_UPDATE | `FOR UPDATE` without `SKIP LOCKED` on batch/queue processing patterns |
| NULL_UNSAFE_ANTIJOIN | `NOT IN (SELECT ...)` instead of `NOT EXISTS`; NULL in subquery yields UNKNOWN |
| DISTINCT_OVER_EXISTS | `SELECT DISTINCT` on joined data; use `EXISTS` semi-join (avoids sort/dedup) |
## Load Sequence
**Foundation** (always load):
- `references/validation.md` — compliance checklist, Effect-SQL alignment, migration safety
**Task-routed references** (load when the task matches):
- `references/ddl.md` — schema design, domain/composite/range types, temporal constraints, generated columns, partitioning, lock levels
- `references/queries.md` — CTE algebra, MERGE, window functions, JSON_TABLE, recursive patterns
- `references/indexes.md` — index type selection, partial indexes, covering indexes, maintenance
- `references/functions.md` — polymorphic functions, custom aggregates, procedures, PL/pgSQL dispatch
- `references/extensions.md` — load when: pgvector, pg_trgm, PostGIS, TimescaleDB, pg_cron, pg_partman, pg_duckdb, embeddings, similarity search, time-series, spatial, partitioning automation, analytics, OLAP, analytical
- `references/security.md` — load when: RLS, row-level security, tenant isolation, privileges, audit, pgaudit
- `references/observability.md` — load when: monitoring, statistics, auto_explain, wait events, lock contention
- `references/performance.md` — load when: tuning, io_uring, JIT, parallel query, vacuum, SSD, NVMe, EXPLAIN
- `references/replication.md` — load when: replication, publications, subscriptions, conflict tracking, CDC
## First-Class Extensions
| Extension | Owns | Load When |
| -------------------- | ----------------------------------------------------- | --------------------------------------- |
| `pgvector` | Vector storage, HNSW/IVFFlat/DiskANN indexes | Embedding search, similarity queries |
| `pgvectorscale` | DiskANN index, Statistical Binary Quantization | >1M vectors, memory-constrained |
| `pg_search` | BM25 full-text via Tantivy, `@@@` operator | Search-quality ranking, hybrid search |
| `pg_trgm` | Trigram similarity, GIN trigram indexes, `%` operator | Fuzzy text search, typo tolerance |
| `PostGIS` | Geometry/geography types, spatial indexes, ST_* funcs | Geospatial queries, proximity search |
| `TimescaleDB` | Hypertables, continuous aggregates, compression | Time-series ingestion, rollup queries |
| `pg_cron` | In-database scheduled jobs | Materialized view refresh, maintenance |
| `pg_partman` | Partition lifecycle management | Non-time-series partitioning |
| `pg_duckdb` | Embedded DuckDB, analytical acceleration, lake access | OLAP queries, Parquet/Iceberg reads |
| `pg_jsonschema` | JSONB validation via JSON Schema CHECK constraints | Structured JSONB columns |
| `btree_gist` | GiST equality operators for EXCLUDE constraints | Range + equality exclusion constraints |
| `bloom` | Bloom filter index for wide-table equality | >5 columns, arbitrary WHERE combos |
| `pg_stat_statements` | Query fingerprinting, execution statistics | Performance analysis, regression detect |
| `pgaudit` | Compliance-grade audit logging (session + object) | SOC 2, HIPAA, PCI-DSS compliance |
## Validation Gate
After writing or modifying SQL, run in order:
1. **Automated lint**: `bash scripts/pg_lint.sh [PATH...]` from this skill directory — anti-pattern detectors (rg-based + structural). Errors (E) block merge; warnings (W) require justification. Supports `--json`, `--sql-only`, `--ts-only`, and `--self-test`.
2. **Manual checklist**: `references/validation.md` — compliance gates not automatable (Effect-SQL alignment, migration safety, lock-level awareness).
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!