Skip to content
Back to skills

Database Designer

ASecurity

Relational schema design — normalization, keys, constraints, and evolution — use when modeling data or reviewing a schema.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 29, 2026
ai-agentsgodatabaseperformancedocumentation

Security analysis

A100/100

Scanned September 29, 2026

npx -y skills add aicodedecode/awesome-muse-skills --skill database-designer --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Database Designer?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Database Designer
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/aicodedecode-database-designer/badge)](https://www.skillsdirectory.com/skills/aicodedecode-database-designer)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: database-designer
description: Relational schema design — normalization, keys, constraints, and evolution — use when modeling data or reviewing a schema.
category: database
---

## Overview

Good schema design is decided once and paid for (or repaid) forever. This skill
covers the principles behind durable relational schemas: normalization done
pragmatically, key selection, constraints as documentation, and how to evolve a
schema without downtime.

## When to use

- Designing a new database schema from requirements
- Reviewing an existing schema for design smells
- Deciding between surrogate keys (UUID/serial) and natural keys
- Planning zero-downtime migrations for a live database
- Choosing data types (timestamps, money, enums, JSON columns)

## Core concepts

**Normalize to 3NF by default, denormalize with evidence.** First normal form
(atomic values, no repeating groups), second (no partial dependencies), third
(no transitive dependencies) eliminate update anomalies. Denormalize only for a
measured query problem — a cached count or a materialized summary — never
preemptively.

**Keys carry meaning.** Primary keys should be stable, unique, and meaningless
if possible: surrogate integer/UUID keys survive business-rule changes that
natural keys (email, username, SKU formats) do not. Foreign keys enforce
referential integrity — declare them; the database is the last line of defense
against orphaned rows.

**Constraints are executable documentation.** `NOT NULL`, `UNIQUE`, `CHECK`, and
foreign keys encode business rules where they cannot be bypassed. Application
code changes; constraints persist. Prefer the database enforcing "an order must
have a customer" over hoping every code path remembers.

**Choose types deliberately.** Money → `NUMERIC`/`DECIMAL`, never float.
Timestamps → timezone-aware types, stored in UTC. Enums → real enum types or
check constraints for closed sets; lookup tables when the set may grow or needs
metadata. Text with a known max → bounded `VARCHAR`; unbounded → `TEXT`.

**Design for evolution.** Every table gets `created_at`/`updated_at` (or
equivalent); soft-delete vs hard-delete is decided per entity; large tables get
their growth strategy up front (partitioning by time, archival policy).

## Practical workflow

1. **Extract entities and relationships** from requirements; write one sentence
   per entity describing its lifecycle (created when? deleted ever?).
2. **Sketch the ER model** — entities, cardinalities, and which side owns the
   relationship. Resolve many-to-many with explicit join tables (they always
   grow attributes later: `created_at`, role, ordering).
3. **Pick keys and types** per the concepts above; name conventions consistently
   (`id` PK, `<entity>_id` FK, `*_at` timestamps).
4. **Add constraints** for every invariant you can state: uniqueness, non-null,
   checks (`CHECK (price >= 0)`), foreign keys with explicit `ON DELETE` behavior.
5. **Review for smells:** god tables (30+ columns doing three jobs), polymorphic
   associations without discipline, nullable FKs that mean two things, missing
   indexes on FK columns.
6. **Plan migrations as expand-then-contract:** add the new column/table →
   dual-write → backfill in batches → switch reads → drop the old. Never rename
   or drop in the same deploy that stops using them.

## Common pitfalls

- **Natural primary keys** (email, phone, government IDs) — they change, they get
  reused, they leak PII into every join and log. Use surrogates; unique-constrain
  the natural key.
- **No foreign keys "for performance"** — the integrity cost dwarfs the tiny
  write overhead; orphaned data is far more expensive than FK checks.
- **Nullable columns with ambiguous meaning** — does `NULL shipped_at` mean "not
  shipped" or "unknown"? Document it or split the state explicitly.
- **Storing lists as comma-separated strings** — violates 1NF, unqueryable,
  unindexable. Use a join table or a proper array/JSON type with a GIN index.
- **Big-bang migrations** — renaming a column and deploying the code that uses
  the new name simultaneously guarantees downtime or errors; expand-contract
  instead.
- **Forgetting the read path** — a perfectly normalized schema that requires
  12 joins for the homepage needs a read model (view, materialized view, or
  cache), designed deliberately rather than discovered in production.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…