home / skills / ehtbanton / claudeskillsrepo / prisma-schema-builder

prisma-schema-builder skill

/prisma-schema-builder

This skill generates complete Prisma schema.prisma files with models, relations, enums, and configuration for TypeScript projects.

npx playbooks add skill ehtbanton/claudeskillsrepo --skill prisma-schema-builder

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
14.7 KB
---
name: prisma-schema-builder
description: Generate Prisma schema files with models, relations, enums, and database configuration for TypeScript ORM setup. Triggers on "create Prisma schema", "generate Prisma model", "prisma.schema for", "database schema Prisma".
---

# Prisma Schema Builder

Generate complete Prisma schema files with models, relationships, enums, and proper configuration.

## Output Requirements

**File Output:** `schema.prisma`
**Format:** Prisma Schema Language (PSL)
**Compatibility:** Prisma 5.x

## When Invoked

Immediately generate a complete Prisma schema with appropriate models, relations, and indexes for the domain.

## Schema Structure

```prisma
// Datasource configuration
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

// Generator configuration
generator client {
  provider = "prisma-client-js"
}

// Models
model User {
  id    Int    @id @default(autoincrement())
  email String @unique
}
```

## Complete Templates

### User Authentication System
```prisma
// schema.prisma

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["fullTextSearch"]
}

// ==========================================
// Enums
// ==========================================

enum UserRole {
  USER
  ADMIN
  MODERATOR
}

enum UserStatus {
  ACTIVE
  INACTIVE
  SUSPENDED
  PENDING_VERIFICATION
}

// ==========================================
// User Management
// ==========================================

model User {
  id            String     @id @default(cuid())
  email         String     @unique
  emailVerified DateTime?  @map("email_verified")
  passwordHash  String?    @map("password_hash")

  // Profile
  firstName     String?    @map("first_name")
  lastName      String?    @map("last_name")
  displayName   String?    @map("display_name")
  avatarUrl     String?    @map("avatar_url")
  bio           String?

  // Account status
  role          UserRole   @default(USER)
  status        UserStatus @default(PENDING_VERIFICATION)

  // Timestamps
  createdAt     DateTime   @default(now()) @map("created_at")
  updatedAt     DateTime   @updatedAt @map("updated_at")
  lastLoginAt   DateTime?  @map("last_login_at")

  // Relations
  sessions      Session[]
  accounts      Account[]
  passwordReset PasswordReset[]

  @@map("users")
}

model Session {
  id           String   @id @default(cuid())
  userId       String   @map("user_id")
  token        String   @unique
  expiresAt    DateTime @map("expires_at")
  ipAddress    String?  @map("ip_address")
  userAgent    String?  @map("user_agent")
  createdAt    DateTime @default(now()) @map("created_at")

  // Relations
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([userId])
  @@index([expiresAt])
  @@map("sessions")
}

model Account {
  id                String  @id @default(cuid())
  userId            String  @map("user_id")
  type              String
  provider          String
  providerAccountId String  @map("provider_account_id")
  refreshToken      String? @map("refresh_token") @db.Text
  accessToken       String? @map("access_token") @db.Text
  expiresAt         Int?    @map("expires_at")
  tokenType         String? @map("token_type")
  scope             String?
  idToken           String? @map("id_token") @db.Text

  // Relations
  user              User    @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([provider, providerAccountId])
  @@index([userId])
  @@map("accounts")
}

model PasswordReset {
  id        String   @id @default(cuid())
  userId    String   @map("user_id")
  token     String   @unique
  expiresAt DateTime @map("expires_at")
  usedAt    DateTime? @map("used_at")
  createdAt DateTime @default(now()) @map("created_at")

  // Relations
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([userId])
  @@map("password_resets")
}

model VerificationToken {
  identifier String
  token      String   @unique
  expiresAt  DateTime @map("expires_at")

  @@unique([identifier, token])
  @@map("verification_tokens")
}
```

### E-commerce Schema
```prisma
// schema.prisma - E-commerce

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

// ==========================================
// Enums
// ==========================================

enum OrderStatus {
  PENDING
  CONFIRMED
  PROCESSING
  SHIPPED
  DELIVERED
  CANCELLED
  REFUNDED
}

enum PaymentStatus {
  PENDING
  COMPLETED
  FAILED
  REFUNDED
}

// ==========================================
// Products
// ==========================================

model Category {
  id          String     @id @default(cuid())
  name        String
  slug        String     @unique
  description String?
  imageUrl    String?    @map("image_url")
  parentId    String?    @map("parent_id")
  sortOrder   Int        @default(0) @map("sort_order")
  isActive    Boolean    @default(true) @map("is_active")
  createdAt   DateTime   @default(now()) @map("created_at")
  updatedAt   DateTime   @updatedAt @map("updated_at")

  // Self-relation for hierarchy
  parent      Category?  @relation("CategoryHierarchy", fields: [parentId], references: [id])
  children    Category[] @relation("CategoryHierarchy")

  // Relations
  products    ProductCategory[]

  @@index([parentId])
  @@index([slug])
  @@map("categories")
}

model Product {
  id             String    @id @default(cuid())
  sku            String    @unique
  name           String
  slug           String    @unique
  description    String?   @db.Text
  price          Decimal   @db.Decimal(10, 2)
  compareAtPrice Decimal?  @map("compare_at_price") @db.Decimal(10, 2)
  cost           Decimal?  @db.Decimal(10, 2)
  quantity       Int       @default(0)
  lowStockAlert  Int       @default(10) @map("low_stock_alert")
  weight         Decimal?  @db.Decimal(8, 3)
  isActive       Boolean   @default(true) @map("is_active")
  isFeatured     Boolean   @default(false) @map("is_featured")
  metadata       Json?
  createdAt      DateTime  @default(now()) @map("created_at")
  updatedAt      DateTime  @updatedAt @map("updated_at")

  // Relations
  categories     ProductCategory[]
  images         ProductImage[]
  variants       ProductVariant[]
  orderItems     OrderItem[]
  cartItems      CartItem[]
  reviews        Review[]

  @@index([sku])
  @@index([slug])
  @@index([isActive, isFeatured])
  @@map("products")
}

model ProductImage {
  id        String   @id @default(cuid())
  productId String   @map("product_id")
  url       String
  altText   String?  @map("alt_text")
  sortOrder Int      @default(0) @map("sort_order")
  isPrimary Boolean  @default(false) @map("is_primary")
  createdAt DateTime @default(now()) @map("created_at")

  // Relations
  product   Product  @relation(fields: [productId], references: [id], onDelete: Cascade)

  @@index([productId])
  @@map("product_images")
}

model ProductVariant {
  id        String   @id @default(cuid())
  productId String   @map("product_id")
  name      String
  sku       String   @unique
  price     Decimal  @db.Decimal(10, 2)
  quantity  Int      @default(0)
  options   Json     // { "color": "red", "size": "M" }
  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")

  // Relations
  product   Product  @relation(fields: [productId], references: [id], onDelete: Cascade)

  @@index([productId])
  @@map("product_variants")
}

model ProductCategory {
  productId  String   @map("product_id")
  categoryId String   @map("category_id")

  product    Product  @relation(fields: [productId], references: [id], onDelete: Cascade)
  category   Category @relation(fields: [categoryId], references: [id], onDelete: Cascade)

  @@id([productId, categoryId])
  @@map("product_categories")
}

// ==========================================
// Customers & Orders
// ==========================================

model Customer {
  id        String    @id @default(cuid())
  email     String    @unique
  firstName String    @map("first_name")
  lastName  String    @map("last_name")
  phone     String?
  createdAt DateTime  @default(now()) @map("created_at")
  updatedAt DateTime  @updatedAt @map("updated_at")

  // Relations
  addresses Address[]
  orders    Order[]
  cart      Cart?
  reviews   Review[]

  @@map("customers")
}

model Address {
  id         String   @id @default(cuid())
  customerId String   @map("customer_id")
  type       String   @default("shipping") // shipping, billing
  firstName  String   @map("first_name")
  lastName   String   @map("last_name")
  line1      String
  line2      String?
  city       String
  state      String?
  postalCode String   @map("postal_code")
  country    String   @db.Char(2) // ISO 3166-1 alpha-2
  phone      String?
  isDefault  Boolean  @default(false) @map("is_default")
  createdAt  DateTime @default(now()) @map("created_at")

  // Relations
  customer   Customer @relation(fields: [customerId], references: [id], onDelete: Cascade)

  @@index([customerId])
  @@map("addresses")
}

model Order {
  id              String        @id @default(cuid())
  orderNumber     String        @unique @map("order_number")
  customerId      String?       @map("customer_id")
  status          OrderStatus   @default(PENDING)
  paymentStatus   PaymentStatus @default(PENDING) @map("payment_status")
  subtotal        Decimal       @db.Decimal(10, 2)
  tax             Decimal       @default(0) @db.Decimal(10, 2)
  shipping        Decimal       @default(0) @db.Decimal(10, 2)
  discount        Decimal       @default(0) @db.Decimal(10, 2)
  total           Decimal       @db.Decimal(10, 2)
  currency        String        @default("USD") @db.Char(3)
  shippingAddress Json?         @map("shipping_address")
  billingAddress  Json?         @map("billing_address")
  notes           String?       @db.Text
  metadata        Json?
  createdAt       DateTime      @default(now()) @map("created_at")
  updatedAt       DateTime      @updatedAt @map("updated_at")

  // Relations
  customer        Customer?     @relation(fields: [customerId], references: [id], onDelete: SetNull)
  items           OrderItem[]

  @@index([customerId])
  @@index([orderNumber])
  @@index([status])
  @@index([createdAt])
  @@map("orders")
}

model OrderItem {
  id        String  @id @default(cuid())
  orderId   String  @map("order_id")
  productId String? @map("product_id")
  sku       String
  name      String
  quantity  Int
  unitPrice Decimal @map("unit_price") @db.Decimal(10, 2)
  total     Decimal @db.Decimal(10, 2)
  metadata  Json?

  // Relations
  order     Order   @relation(fields: [orderId], references: [id], onDelete: Cascade)
  product   Product? @relation(fields: [productId], references: [id], onDelete: SetNull)

  @@index([orderId])
  @@map("order_items")
}

// ==========================================
// Cart
// ==========================================

model Cart {
  id         String     @id @default(cuid())
  customerId String?    @unique @map("customer_id")
  sessionId  String?    @unique @map("session_id")
  expiresAt  DateTime?  @map("expires_at")
  createdAt  DateTime   @default(now()) @map("created_at")
  updatedAt  DateTime   @updatedAt @map("updated_at")

  // Relations
  customer   Customer?  @relation(fields: [customerId], references: [id], onDelete: Cascade)
  items      CartItem[]

  @@map("carts")
}

model CartItem {
  id        String  @id @default(cuid())
  cartId    String  @map("cart_id")
  productId String  @map("product_id")
  quantity  Int

  // Relations
  cart      Cart    @relation(fields: [cartId], references: [id], onDelete: Cascade)
  product   Product @relation(fields: [productId], references: [id], onDelete: Cascade)

  @@unique([cartId, productId])
  @@map("cart_items")
}

// ==========================================
// Reviews
// ==========================================

model Review {
  id         String   @id @default(cuid())
  productId  String   @map("product_id")
  customerId String   @map("customer_id")
  rating     Int      // 1-5
  title      String?
  content    String?  @db.Text
  isVerified Boolean  @default(false) @map("is_verified")
  createdAt  DateTime @default(now()) @map("created_at")
  updatedAt  DateTime @updatedAt @map("updated_at")

  // Relations
  product    Product  @relation(fields: [productId], references: [id], onDelete: Cascade)
  customer   Customer @relation(fields: [customerId], references: [id], onDelete: Cascade)

  @@unique([productId, customerId])
  @@index([productId])
  @@map("reviews")
}
```

## Field Type Reference

### Scalar Types
| Prisma Type | PostgreSQL | MySQL | Description |
|-------------|------------|-------|-------------|
| String | TEXT | VARCHAR(191) | Text |
| Int | INTEGER | INT | Integer |
| BigInt | BIGINT | BIGINT | Large integer |
| Float | DOUBLE PRECISION | DOUBLE | Floating point |
| Decimal | DECIMAL | DECIMAL | Precise decimal |
| Boolean | BOOLEAN | BOOLEAN | True/false |
| DateTime | TIMESTAMP(3) | DATETIME(3) | Date and time |
| Json | JSONB | JSON | JSON data |
| Bytes | BYTEA | LONGBLOB | Binary data |

### Database-Specific Types
```prisma
// PostgreSQL specific
field String @db.VarChar(255)
field String @db.Text
field Decimal @db.Decimal(10, 2)
field String @db.Char(2)

// MySQL specific
field String @db.VarChar(255)
field String @db.LongText
field Int @db.UnsignedInt
```

## Relation Patterns

### One-to-Many
```prisma
model User {
  posts Post[]
}

model Post {
  authorId String
  author   User   @relation(fields: [authorId], references: [id])
}
```

### Many-to-Many (Implicit)
```prisma
model Post {
  tags Tag[]
}

model Tag {
  posts Post[]
}
```

### Many-to-Many (Explicit)
```prisma
model Post {
  categories PostCategory[]
}

model Category {
  posts PostCategory[]
}

model PostCategory {
  postId     String
  categoryId String
  post       Post     @relation(fields: [postId], references: [id])
  category   Category @relation(fields: [categoryId], references: [id])

  @@id([postId, categoryId])
}
```

## Validation Checklist

Before outputting, verify:
- [ ] Datasource configured with env variable
- [ ] Generator block present
- [ ] All relations have inverse defined
- [ ] Foreign keys have `@index`
- [ ] Unique fields have `@unique`
- [ ] `@@map` used for table names (snake_case)
- [ ] `@map` used for column names (snake_case)
- [ ] Cascade deletes appropriate

## Example Invocations

**Prompt:** "Create Prisma schema for a blog with posts, tags, and comments"
**Output:** Complete `schema.prisma` with User, Post, Tag, Comment models.

**Prompt:** "Generate Prisma schema for SaaS multi-tenant app"
**Output:** Complete `schema.prisma` with Organization, User, Membership, Team models.

**Prompt:** "Prisma schema for task management application"
**Output:** Complete `schema.prisma` with Project, Task, User, Comment, Label models.

Overview

This skill generates complete Prisma schema.prisma files tailored for TypeScript projects using Prisma 5.x. It produces models, relations, enums, indexes, and datasource/generator blocks ready for immediate use. The output focuses on practical, production-ready patterns for authentication, e-commerce, and common domain models.

How this skill works

Provide the domain or trigger phrase (for example: "create Prisma schema" or "prisma.schema for e-commerce") and the skill builds a full Prisma Schema Language file. It chooses appropriate scalar and database-specific types, maps fields and column names, defines relations (one-to-many, many-to-many explicit/implicit), and adds indexes and constraints. The result is a single schema.prisma compatible with PostgreSQL or MySQL with Prisma client generator configured.

When to use it

  • Bootstrapping a new TypeScript backend with Prisma ORM
  • Generating domain schemas for authentication, e-commerce, CMS, or custom models
  • Creating reference schemas for database migrations and typesafe client generation
  • Speeding up prototyping by producing ready-to-run schema.prisma files
  • Standardizing schema patterns across projects or teams

Best practices

  • Specify provider and DATABASE_URL environment variable in the datasource block
  • Use cuid()/autoincrement() and appropriate unique constraints for stable identifiers
  • Add @@index and @@unique directives for query-critical fields (email, sku, orderNumber)
  • Map database column names with @map for backward compatibility when needed
  • Prefer explicit join tables for many-to-many when you need extra metadata on relationships

Example use cases

  • Generate a complete authentication schema with User, Session, Account, PasswordReset, and VerificationToken models
  • Create an e-commerce schema including Product, Category, Variant, Cart, Order, and Review models with enums for statuses
  • Produce a simple blog schema with Post, Author, Tag and PostTag join table
  • Convert a domain description (fields and relations) into a ready-to-run schema.prisma file

FAQ

Which Prisma version is this schema compatible with?

Schemas are generated for Prisma 5.x and use Prisma Schema Language patterns compatible with that version.

Can I target PostgreSQL and MySQL?

Yes. The skill uses provider-agnostic types by default and includes db-specific annotations (@db.*) when you request Postgres- or MySQL-specific fields.

Will it add indexes and constraints automatically?

Yes. The generator adds common @@index, @@unique, and @@id directives for fields that benefit from them (identifiers, foreign keys, lookup fields).