Database schema designer
Use when designing new database tables from requirements, reviewing a schema for normalisation or performance issues, adding multi-tenancy, planning a breaking migration, or generating TypeScript/Python types from a schema. Triggers on "design the schema", "ERD", "table relationships", "schema migration", "normalise this", or "database model".From its SKILL.md
npx -y skills add tmj-90/gaffer --skill database-schema-designerAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 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
4.8 KB, ~1.0k tokens by cl100k_base, as published. Nobody here has run it
Design schemas that survive production
Normalise first. Index for query patterns. Never sacrifice data integrity for convenience.
Design process
Step 1 — Requirements → Entities
Extract nouns from the requirement. Each noun that has attributes and participates in relationships is likely an entity. Resist making everything a single wide table.
Step 2 — Relationships
Identify cardinality before choosing the table structure:
| Relationship | Implementation |
|---|---|
| 1:1 | Foreign key on the less-common side (or same table if always loaded together) |
| 1:N | Foreign key on the N side |
| M:N | Junction table with FK to both sides; add attributes to the junction if needed |
Step 3 — Normalisation
Target 3NF for transactional data:
- 1NF — atomic values; no repeating groups; primary key identifies each row.
- 2NF — no partial dependencies (non-key column depends on the whole PK, not a subset).
- 3NF — no transitive dependencies (non-key column depends only on the PK, not on another non-key column).
Denormalise deliberately for read-heavy analytics tables — document the trade-off.
Standard conventions
- Primary key:
id(UUID v7 for distributed systems; BIGSERIAL for single-node). - Timestamps:
created_at TIMESTAMPTZ DEFAULT now(),updated_at TIMESTAMPTZ DEFAULT now(). - Soft delete:
deleted_at TIMESTAMPTZnullable — add a partial indexWHERE deleted_at IS NULL. - Audit trail: separate
audit_logtable withentity_type,entity_id,action,actor_id,changed_at,before,after. - Multi-tenancy:
tenant_idon every tenant-scoped table; composite primary key or FK constraint; RLS policy.
Index strategy
- Index every foreign key (databases do not do this automatically).
- Add composite indexes for the most common
WHERE col1 = ? AND col2 = ?patterns. - Partial indexes for filtered queries (
WHERE deleted_at IS NULL,WHERE status = 'active'). - Covering indexes (
INCLUDE (col)) to avoid heap lookups on hot read paths. - Drop indexes that are never used — they slow writes.
Migration safety
| Change | Safe? | Notes |
|---|---|---|
| Add nullable column | Yes | |
| Add NOT NULL with default | Risky on large tables | Add nullable, backfill, add constraint |
| Rename column | No | Add new, backfill, drop old — across deploys |
| Drop column | No | Mark unused, deploy, then drop |
| Add index | Yes (CONCURRENT) | CREATE INDEX CONCURRENTLY — never blocking |
| Change column type | No | New column + backfill pattern |
Steps
- Read the lore + existing schema.
search_lorefor ORM conventions, migration tool (Drizzle/Prisma/Alembic), naming rules, and existing patterns. Extend; don't contradict. - Extract entities and relationships from the requirements. Draw the ERD (Mermaid is fine) before writing DDL.
- Normalise to 3NF. Document any deliberate denormalisation.
- Write migrations. Use the repo's migration tool. Each migration: one logical change, reversible (
up/down), idempotent. - Add indexes. At minimum: every FK; composite for the top query patterns identified from the ticket.
- Generate types. Derive TypeScript interfaces or Python Pydantic models from the schema — do not hand-write them separately.
- Verify. Run migrations against a real database; confirm
EXPLAIN ANALYZEon the primary query patterns shows index scans, not sequential scans. Record evidence.
Review checklist
- 3NF achieved — no partial or transitive dependencies, or denormalisation is documented.
- Every FK indexed — check
pg_indexesor equivalent. - Migrations reversible —
downmigration exists and tested. - No blocking DDL — index creation uses
CONCURRENTLY; large table alterations use the add-backfill-constraint pattern. - Timestamps on every table —
created_at,updated_at. - Types generated — not hand-written from the schema.
Rules
- Never rename a column in a single migration on a live table — three-deploy pattern only.
CREATE INDEX CONCURRENTLYalways — blocking index creation on production tables is a SEV2.- Audit trail for every table that stores user-facing data with compliance implications.
Capture lore
ORM choice, migration tool, naming conventions, UUID strategy, and RLS policy are high-value schema lore — call suggest_lore with tags: [database, schema, migrations].
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.