Skip to content
Skillpedia
Databases41k · #4840

postgresql-table-design

Has your agent design and review the structure of tables in PostgreSQL databases. It ensures the design is efficient, secure, and follows best practices to optimize performance.

What it does

This agent helps design and review table structures for PostgreSQL databases. It suggests best practices for data types, indexes, and rules to ensure your database performs well.

When to use it

  • ✓When creating a new database.
  • ✓When choosing the right data types for your columns.
  • ✓When deciding how to organize your data for best performance.

Example of what to ask your AI

“How should I create a table to store customer information, ensuring emails are unique?”

Want more? Open the sections below.

How to use

The easiest way: copy the message below and paste it into Claude, ChatGPT, Cursor or any AI. It reads the skill and follows the instructions.

Skill link

https://github.com/wshobson/agents/blob/main/plugins/database-design/skills/postgresql-table-design/SKILL.md

Ready-to-paste message

Use this skill to help me: https://github.com/wshobson/agents/blob/main/plugins/database-design/skills/postgresql-table-design/SKILL.md Read the SKILL.md file at that link and follow its instructions for my task.
How it works

It analyzes your needs and suggests the best column options, indexes, and PostgreSQL-specific rules, considering performance and best practices.

Installation

Easiest way: copy the skill link and paste it into Claude, ChatGPT or Cursor asking it to follow the instructions.

In the terminal (Claude Code, Codex, Cursor), in your project folder:

npx skills add wshobson/agents --skill postgresql-table-design

Or download just the file:

curl -L https://raw.githubusercontent.com/wshobson/agents/main/plugins/database-design/skills/postgresql-table-design/SKILL.md -o SKILL.md
Technical content (original SKILL.md)

Original text by the author, straight from GitHub.

PostgreSQL Table Design

When to Use

  • Designing a new PostgreSQL schema, or reviewing one before it ships.
  • Choosing column types, keys, constraints, or indexes for PostgreSQL specifically.
  • Deciding whether and how to partition a large table, or how to store semi-structured data.
  • Planning a schema change on a live database without downtime.

The rules and decision points for a PostgreSQL schema. The full data-type catalog, workload patterns (update-heavy, insert-heavy, upsert, schema evolution), extensions, JSONB indexing, and worked DDL examples are in references/details.md; open it when a section below points there.

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; use UUID only 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.
  • Add NOT NULL everywhere it is 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 integers; DOUBLE PRECISION for floats (or NUMERIC for exact decimal arithmetic).

PostgreSQL Gotchas

  • Identifiers: unquoted → lowercased. Avoid quoted/mixed-case names; use snake_case.
  • Unique + NULLs: UNIQUE allows multiple NULLs. Use UNIQUE NULLS NOT DISTINCT (...) (PG15+) to restrict to one NULL.
  • FK indexes: PostgreSQL does not auto-index FK columns. Add them.
  • No silent coercions: length/precision overflows error out (no truncation). Inserting 999 into NUMERIC(2,0) fails, unlike databases that silently truncate or round.
  • Sequences/identity have gaps (normal; don't "fix"). Rollbacks, crashes, and concurrent transactions leave gaps (1, 2, 5, 6...).
  • Heap storage: no clustered PK by default; CLUSTER is a one-off reorganization, not maintained on later inserts.
  • MVCC: updates/deletes leave dead tuples; vacuum handles them—design to avoid hot wide-row churn.

Data Types

  • IDs: BIGINT GENERATED ALWAYS AS IDENTITY; UUID for distributed or opaque IDs, generated with uuidv7() (PG18+) or gen_random_uuid().
  • Numbers: BIGINT unless storage is critical; DOUBLE PRECISION over REAL; NUMERIC(p,s) for money and exact decimals.
  • Strings: TEXT, with CHECK (LENGTH(col) <= n) when a limit is needed; BYTEA for binary. Case-insensitive lookups: expression index on LOWER(col), or CITEXT when a constraint must be case-insensitive.
  • Time: TIMESTAMPTZ, DATE, INTERVAL. now() is transaction start; clock_timestamp() is wall clock.
  • Booleans: BOOLEAN NOT NULL unless tri-state is required.
  • Enums: CREATE TYPE ... AS ENUM only for small, stable sets; evolving business values get TEXT + CHECK or a lookup table.
  • JSONB over JSON, indexed with GIN, for optional/semi-structured attributes only.
  • Arrays, ranges, network, geometric, full-text, domain, composite, and vector types, plus TOAST storage and collation control: see references/details.md.

Types to avoid

Avoid Use instead
timestamp (without time zone) timestamptz
char(n), varchar(n) text (+ CHECK on length if needed)
money numeric
timetz timestamptz
timestamptz(0) or any precision timestamptz
serial generated always as identity

Constraints

  • PK: implicit UNIQUE + NOT NULL; creates a B-tree index.
  • FK: specify ON DELETE/UPDATE (CASCADE, RESTRICT, SET NULL, SET DEFAULT). Index the referencing column. Use DEFERRABLE INITIALLY DEFERRED for circular dependencies checked at commit.
  • UNIQUE: creates a B-tree index; allows multiple NULLs unless NULLS NOT DISTINCT (PG15+). Prefer NULLS NOT DISTINCT unless duplicate NULLs are wanted.
  • CHECK: row-local; NULL passes (three-valued logic). Combine with NOT NULL: price NUMERIC NOT NULL CHECK (price > 0).
  • EXCLUDE: prevents overlaps with operators, e.g. EXCLUDE USING gist (room_id WITH =, booking_period WITH &&) stops double-booking. Needs a GiST-capable type.

Indexing

…

FAQ

Why shouldn't I use 'varchar(n)'?

'Text' is generally preferred in PostgreSQL as it has no size limits and similar performance. You can add a CHECK constraint if you need to limit the length.

Does PostgreSQL automatically create indexes for foreign keys?

No, PostgreSQL does not automatically create indexes for foreign key columns. You need to add them manually for good query performance.

What are PostgreSQL 'gotchas'?

'Gotchas' are quirks or unexpected behaviors in PostgreSQL that can cause issues if you're not aware of them, such as how identifiers are handled or the lack of automatic indexing on foreign keys.

Details

Original description by the author

Use this skill when designing or reviewing a PostgreSQL-specific schema. Covers best-practices, data types, indexing, constraints, performance patterns, and advanced features

repo: wshobson/agents

Popularity

GitHub stars
41k
Ranking position
#4840
License
MIT
Updated
10/15/2026

Is this skill useful?

0

Sign in to vote.

Comments

  • …

More skills from this repository

Similar skills