sickn33/antigravity-awesome-skills/postgresql
- community
Checking that the SKILL.md file is still in the repository.
Design a PostgreSQL-specific schema. Covers best-practices, data types, indexing, constraints, performance patterns, and advanced features
Install
npx vskill@latest install sickn33/antigravity-awesome-skills/postgresqlSKILL.md
PostgreSQL Table Design
Use this skill when
- Designing a schema for PostgreSQL
- Selecting data types and constraints
- Planning indexes, partitions, or RLS policies
- Reviewing tables for scale and maintainability
Do not use this skill when
- You are targeting a non-PostgreSQL database
- You only need query tuning without schema changes
- You require a DB-agnostic modeling guide
Instructions
- Capture entities, access patterns, and scale targets (rows, QPS, retention).
- Choose data types and constraints that enforce invariants.
- Add indexes for real query paths and validate with
EXPLAIN. - Plan partitioning or RLS where required by scale or access control.
- Review migration impact and apply changes safely.
Safety
- Avoid destructive DDL on production without backups and a rollback plan.
- Use migrations and staging validation before applying schema changes.
Core Rules
- Define a PRIMARY KEY for reference tables (users, orders, etc.). Not always needed for time-series/event/log data. When used, prefer
BIGINT GENERATED ALWAYS AS IDENTITY; useUUIDonly when global uniqueness/opacity is needed. - Normalize first (to 3NF) to eliminate data redundancy and update anomalies; denormalize only for measured, high-ROI reads where join performance is proven problematic. Premature denormalization creates maintenance burden.
- Add NOT NULL everywhere it’s semantically required; use DEFAULTs for common values.
- Create indexes for access paths you actually query: PK/unique (auto), FK columns (manual!), frequent filters/sorts, and join keys.
- Prefer TIMESTAMPTZ for event time; NUMERIC for money; TEXT for strings; BIGINT for integer values, DOUBLE PRECISION for floats (or
NUMERICfor exact decimal arithmetic).
PostgreSQL “Gotchas”
- Identifiers: unquoted → lowercased. Avoid quoted/mixed-case names. Convention: use
snake_casefor table/column names. - Unique + NULLs: UNIQUE allows multiple NULLs. Use
UNIQUE NULLS NOT DISTINCT (...)(PG15+) to restrict to one NULL. - FK indexes: PostgreSQL does not auto-index referencing FK columns. Assess indexes for joins and parent updates/deletes against write costs.
- No silent coercions: some length/precision overflows error out, while numeric scale coercion can round and explicit character casts can truncate. Example: inserting 999 into
NUMERIC(2,0)fails with error, unlike some databases that silently truncate or round. - Sequences/identity have gaps (normal; don't "fix"). Rollbacks, crashes, and concurrent transactions create gaps in ID sequences (1, 2, 5, 6...). This is expected behavior—don't try to make IDs consecutive.
- Heap storage: no clustered PK by default (unlike SQL Server/MySQL InnoDB);
CLUSTERis one-off reorganization, not maintained on subsequent inserts. Heap physical order is not guaranteed and changes with updates and maintenance; query order requires ORDER BY. - MVCC: updates/deletes leave dead tuples; vacuum handles them—design to avoid hot wide-row churn.
Data Types
- IDs:
BIGINT GENERATED ALWAYS AS IDENTITYpreferred (GENERATED BY DEFAULTalso fine);UUIDwhen merging/federating/used in a distributed system or for opaque IDs. Generate withuuidv7()(preferred if using PG18+) orgen_random_uuid()(if using an older PG version). - Integers: prefer
BIGINTunless storage space is critical;INTEGERfor smaller ranges; avoidSMALLINTunless constrained. - Floats: prefer
DOUBLE PRECISIONoverREALunless storage space is critical. UseNUMERICfor exact decimal arithmetic. - Strings: prefer
TEXT; if length limits needed, useCHECK (LENGTH(col) <= n)instead ofVARCHAR(n); avoidCHAR(n). UseBYTEAfor binary data. TOAST decisions depend on total tuple size, compressibility and storage settings, not an unconditional per-value 2KB threshold. TOAST storage:PLAIN(no TOAST),EXTENDED(compress + out-of-line),EXTERNAL(out-of-line, no compress),MAIN(compress, keep in-line if possible). DefaultEXTENDEDusually optimal. Control withALTER TABLE tbl ALTER COLUMN col SET STORAGE strategyandALTER TABLE tbl SET (toast_tuple_target = 4096)for threshold. Case-insensitive: for locale/accent handling use non-deterministic collations; for plain ASCII use expression indexes onLOWER(col)(preferred unless column needs case-insensitive PK/FK/UNIQUE) orCITEXT. - Money:
NUMERIC(p,s)(never float). - Time:
TIMESTAMPTZfor timestamps;DATEfor date-only;INTERVALfor durations. AvoidTIMESTAMP(without timezone). Usenow()for transaction start time,clock_timestamp()for current wall-clock time. - Booleans:
BOOLEANwithNOT NULLconstraint unless tri-state values are required. - Enums:
CREATE TYPE ... AS ENUMfor small, stable sets (e.g. US states, days of week). For business-logic-driven and evolving values (e.g. order statuses) → use TEXT (or INT) + CHECK or lookup table. - Arrays:
TEXT[],INTEGER[], etc. Use for ordered lists where you query elements. Index with GIN for containment (@>,<@) and overlap (&&) queries. Access:arr[1](1-indexed),arr[1:3](slicing). Good for tags, categories; avoid for relations—use junction tables instead. Literal syntax:'{val1,val2}'orARRAY[val1,val2]. - Range types:
daterange,numrange,tstzrangefor intervals. Support overlap (&&), containment (@>), operators. Index with GiST. Good for scheduling, versioning, numeric ranges. Pick a bounds scheme and use it consistently; prefer[)(inclusive/exclusive) by default. - Network types:
INETfor IP addresses,CIDRfor network ranges,MACADDRfor MAC addresses. Support network operators (<<,>>,&&). - Geometric types:
POINT,LINE,POLYGON,CIRCLEfor 2D spatial data. Index with GiST. Consider PostGIS for advanced spatial features. - Text search:
TSVECTORfor full-text search documents,TSQUERYfor search queries. Indextsvectorwith GIN. Always specify language:to_tsvector('english', col)andto_tsquery('english', 'query'). Never use single-argument versions. This applies to both index expressions and queries. - Domain types:
CREATE DOMAIN email AS TEXT CHECK (VALUE ~ '^[^@]+@[^@]+$')for reusable custom types with validation. Enforces constraints across tables. - Composite types:
CREATE TYPE address AS (street TEXT, city TEXT, zip TEXT)for structured data within columns. Access with(col).fieldsyntax. - JSONB: preferred over JSON; index with GIN. Use only for optional/semi-structured attrs. ONLY use JSON if the original ordering of the contents MUST be preserved.
- Vector types:
vectortype bypgvectorfor vector similarity search for embeddings.
Do not use the following data types
- DO NOT use
timestamp(without time zone); DO usetimestamptzinstead. - DO NOT use
char(n)orvarchar(n); DO usetextinstead. - DO NOT use
moneytype; DO usenumericinstead. - DO NOT use
timetztype; DO usetimestamptzinstead. - DO NOT use
timestamptz(0)or any other precision specification; DO usetimestamptzinstead - DO NOT use
serialtype; DO usegenerated always as identityinstead.
Table Types
- Regular: default; fully durable, logged.
- TEMPORARY: normally session-scoped and dropped at session end; ON COMMIT can alter lifecycle, and data is not WAL-logged. Faster for scratch work.
- UNLOGGED: persistent but not crash-safe. Faster writes; good for caches/staging.
Row-Level Security
Enable with ALTER TABLE tbl ENABLE ROW LEVEL SECURITY. Create policies: CREATE POLICY user_access ON orders FOR SELECT TO app_users USING (user_id = current_user_id()). The current_user_id() function is an application-specific placeholder, not built in. Define a trusted identity function, test policies as non-owner roles and consider owner/BYPASSRLS bypass and FORCE ROW LEVEL SECURITY.
Constraints
- PK: implicit UNIQUE + NOT NULL; creates a B-tree index.
- FK: specify
ON DELETE/UPDATEaction (CASCADE,RESTRICT,SET NULL,SET DEFAULT). Add explicit index on referencing column—speeds up joins and prevents locking issues on parent deletes/updates. UseDEFERRABLE INITIALLY DEFERREDfor circular FK dependencies checked at transaction end. - UNIQUE: creates a B-tree index; allows multiple NULLs unless
NULLS NOT DISTINCT(PG15+). Standard behavior:(1, NULL)and(1, NULL)are allowed. WithNULLS NOT DISTINCT: only one(1, NULL)allowed. PreferNULLS NOT DISTINCTunless you specifically need duplicate NULLs. - CHECK: row-local constraints; NULL values pass the check (three-valued logic). Example:
CHECK (price > 0)allows NULL prices. Combine withNOT NULLto enforce:price NUMERIC NOT NULL CHECK (price > 0). - EXCLUDE: prevents overlapping values using operators.
EXCLUDE USING gist (room_id WITH =, booking_period WITH &&)prevents double-booking rooms. Requires appropriate index type (often GiST).
Indexing
- B-tree: default for equality/range queries (
=,<,>,BETWEEN,ORDER BY) - Composite: order matters—index used if equality on leftmost prefix (
WHERE a = ? AND b > ?uses index on(a,b), while a predicate only on b may still use a scan or version-dependent skip scan; inspect the actual plan). Put most selective/frequently filtered columns first. - Covering:
CREATE INDEX ON tbl (id) INCLUDE (name, email)- includes non-key columns for index-only scans with heap visits avoided only where MVCC visibility permits. - Partial: for hot subsets (
WHERE status = 'active'→CREATE INDEX ON tbl (user_id) WHERE status = 'active'). The planner must prove the query predicate implies the index predicate; generic parameterized plans and cost choices can prevent its use. - Expression: for computed search keys (
CREATE INDEX ON tbl (LOWER(email))). Expression must match exactly in WHERE clause:WHERE LOWER(email) = 'user@example.com'. - GIN: JSONB containment/existence, arrays (
@>,?), full-text search (@@) - GiST: ranges, geometry, exclusion constraints
- BRIN: very large, naturally ordered data (time-series)—minimal storage overhead. Effective when row order on disk correlates with indexed column (insertion order or after
CLUSTER).
Partitioning
- Use for very large tables (>100M rows) where queries consistently filter on partition key (often time/date).
- Alternate use: use for tables where data maintenance tasks dictates e.g. data pruned or bulk replaced periodically
- RANGE: common for time-series (
PARTITION BY RANGE (created_at)). Create partitions:CREATE TABLE logs_2024_01 PARTITION OF logs FOR VALUES FROM ('2024-01-01') TO ('2024-02-01'). TimescaleDB automates time-based or ID-based partitioning with retention policies and compression. - LIST: for discrete values (
PARTITION BY LIST (region)). Example:FOR VALUES IN ('us-east', 'us-west'). - HASH: for even distribution when no natural key (
PARTITION BY HASH (user_id)). Creates N partitions with modulus. - Partition pruning uses declarative partition bounds and can occur at planning/execution time. Constraint exclusion uses CHECK constraints and is a separate mechanism.
- Prefer declarative partitioning or hypertables. Do NOT use table inheritance.
- Limitations: no global UNIQUE constraints—include partition key in PK/UNIQUE. Modern PostgreSQL supports foreign keys on partitioned tables; check the target version and constraint rules, rather than replacing integrity with ad hoc triggers.
Special Considerations
Update-Heavy Tables
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 95 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/postgresql/SKILL.md
Popularity
- Repository stars
- 27,508
- Repository forks
- 4,631
- Repository npm downloads, 7 days
- 6,951
- 7-day trend score
- 72
Stars and forks are for the whole GitHub repository, not this skill alone. Downloads are for the repository's npm package. Refreshed 21 Mar 2026, 7 months ago.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/sickn33/antigravity-awesome-skills/postgresql)