Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
spencerpauly avatar

Database Design

  • 268 installs
  • 655 repo stars
  • Updated August 2, 2026
  • spencerpauly/awesome-cursor-skills

Helps with design & ui/ux tasks.

About

database-design is a Claude Code skill for design & ui/ux. It helps solo builders move faster with AI-assisted coding.

  • database-design
  • Design & UI/UX
  • AI-coding skill

Database Design by the numbers

  • 268 all-time installs (skills.sh)
  • +29 installs in the week ending Aug 5, 2026 (Skillselion tracking)
  • Ranked #853 of 1,880 Design & UI/UX skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/spencerpauly/awesome-cursor-skills --skill database-design

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs268
repo stars655
Last updatedAugust 2, 2026
Repositoryspencerpauly/awesome-cursor-skills

What it does

Helps with design & ui/ux tasks.

Files

SKILL.mdMarkdownGitHub ↗

Database Design

Design a database schema from requirements.

Workflow

1. Identify Entities

From the requirements, extract the core entities (nouns):

  • Users, Teams, Projects, Tasks, Comments, etc.
  • Each entity becomes a table

2. Define Relationships

RelationshipImplementation
One-to-oneForeign key with unique constraint, or embed in same table
One-to-manyForeign key on the "many" side
Many-to-manyJunction/join table
Self-referentialForeign key pointing to same table (e.g. parent_id)

3. Design the Schema

For each table:

CREATE TABLE users (
  id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  email       TEXT NOT NULL UNIQUE,
  name        TEXT NOT NULL,
  avatar_url  TEXT,
  created_at  TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at  TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE projects (
  id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name        TEXT NOT NULL,
  owner_id    UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  created_at  TIMESTAMPTZ NOT NULL DEFAULT now()
);

4. Apply Best Practices

Primary keys:

  • Use UUID for distributed systems or public-facing IDs
  • Use SERIAL/BIGSERIAL for internal-only IDs (faster joins)

Timestamps:

  • Always add created_at and updated_at
  • Use TIMESTAMPTZ (with timezone), never TIMESTAMP

Naming:

  • Tables: plural snake_case (users, project_members)
  • Columns: singular snake_case (user_id, created_at)
  • Indexes: idx_<table>_<columns> (idx_users_email)

Constraints:

  • NOT NULL on everything unless it's genuinely optional
  • UNIQUE on natural keys (email, slug, external IDs)
  • REFERENCES with ON DELETE behavior (CASCADE, SET NULL, RESTRICT)
  • CHECK constraints for enums or value ranges

5. Add Indexes

-- For columns you filter/sort by frequently
CREATE INDEX idx_projects_owner_id ON projects(owner_id);

-- For unique lookups
CREATE UNIQUE INDEX idx_users_email ON users(email);

-- Composite for common query patterns
CREATE INDEX idx_tasks_project_status ON tasks(project_id, status);

When to index:

  • Foreign keys (almost always)
  • Columns in WHERE clauses
  • Columns in ORDER BY
  • Columns in JOIN conditions

When NOT to index:

  • Small tables (<1000 rows)
  • Columns with low cardinality (boolean, status with 3 values)
  • Columns that are rarely queried

6. ORM Setup

Prisma:

model User {
  id        String   @id @default(uuid())
  email     String   @unique
  name      String
  projects  Project[]
  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")
  @@map("users")
}

Drizzle:

export const users = pgTable('users', {
  id: uuid('id').primaryKey().defaultRandom(),
  email: text('email').notNull().unique(),
  name: text('name').notNull(),
  createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
});

Common Patterns

Soft deletes: Add deleted_at TIMESTAMPTZ instead of actually deleting rows Audit log: Separate audit_events table with entity_type, entity_id, action, actor_id, payload Tags/labels: Junction table (task_tags) with task_id + tag_id Tree/hierarchy: parent_id self-reference, or materialized path (/1/4/7/) Polymorphic associations: Use entity_type + entity_id columns (avoid if possible, prefer separate FKs)

Tips

  • Start normalized (3NF), denormalize only when you have measured performance problems
  • Don't store derived data unless you have a caching/invalidation strategy
  • Use database enums or check constraints for status fields, not free-text
  • Always think about what happens when you delete a parent record

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.