Create new

Schema

Every Prisma model in launch.now — what it stores and how it relates to the rest of the app.

The full schema lives in prisma/schema.prisma. It's split into two groups: Better Auth tables (managed automatically) and app models (yours to extend).


Better Auth tables

These are created and managed by Better Auth. You read from them but rarely write directly — use the auth client instead.

model User {
  id            String    @id @default(cuid())
  name          String
  email         String    @unique
  emailVerified Boolean   @default(false)
  image         String?
  createdAt     DateTime  @default(now())
  updatedAt     DateTime  @updatedAt

  // Better Auth relations
  sessions      Session[]
  accounts      Account[]

  // 2FA
  twoFactorEnabled Boolean  @default(false)
  twoFactorSecret  String?
  twoFactorBackupCodes String?

  // App relations
  subscription  Subscription?
  memberships   OrganizationMember[]

  @@map("user")
}

model Session {
  id        String   @id @default(cuid())
  userId    String
  token     String   @unique
  expiresAt DateTime
  ipAddress String?
  userAgent String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

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

  @@map("session")
}

model Account {
  id                    String  @id @default(cuid())
  userId                String
  accountId             String
  providerId            String
  accessToken           String?
  refreshToken          String?
  accessTokenExpiresAt  DateTime?
  refreshTokenExpiresAt DateTime?
  scope                 String?
  password              String?   // hashed — only set for email/password accounts
  createdAt             DateTime  @default(now())
  updatedAt             DateTime  @updatedAt

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

  @@map("account")
}

model Verification {
  id         String   @id @default(cuid())
  identifier String
  value      String
  expiresAt  DateTime
  createdAt  DateTime @default(now())
  updatedAt  DateTime @updatedAt

  @@map("verification")
}

model Passkey {
  id           String   @id @default(cuid())
  userId       String
  credentialId String   @unique
  publicKey    String
  counter      Int
  deviceType   String
  backedUp     Boolean  @default(false)
  transports   String?
  createdAt    DateTime @default(now())

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

  @@map("passkey")
}

Never delete or rename Better Auth tables. If you need to add columns to User (e.g. onboardingCompleted, role), add them directly — Prisma merges your additions with Better Auth's requirements.


App models

These are the core SaaS models. Extend them freely.

model Subscription {
  id                   String    @id @default(cuid())
  userId               String    @unique
  stripeCustomerId     String    @unique
  stripeSubscriptionId String?   @unique
  stripePriceId        String?
  status               String    @default("inactive")
                                 // active | trialing | past_due | canceled | inactive
  currentPeriodStart   DateTime?
  currentPeriodEnd     DateTime?
  cancelAtPeriodEnd    Boolean   @default(false)
  createdAt            DateTime  @default(now())
  updatedAt            DateTime  @updatedAt

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

  @@map("subscription")
}

model Organization {
  id        String   @id @default(cuid())
  name      String
  slug      String   @unique
  logo      String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  members  OrganizationMember[]
  invites  OrganizationInvite[]

  @@map("organization")
}

model OrganizationMember {
  id             String   @id @default(cuid())
  organizationId String
  userId         String
  role           OrgRole  @default(MEMBER)
  createdAt      DateTime @default(now())

  organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
  user         User         @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([organizationId, userId])
  @@map("organization_member")
}

model OrganizationInvite {
  id             String    @id @default(cuid())
  organizationId String
  email          String
  role           OrgRole   @default(MEMBER)
  token          String    @unique @default(cuid())
  expiresAt      DateTime
  acceptedAt     DateTime?
  createdAt      DateTime  @default(now())

  organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)

  @@map("organization_invite")
}

enum OrgRole {
  OWNER
  ADMIN
  MEMBER
}

Extending the User model

Add your own fields directly to the User model. Better Auth ignores unknown fields:

model User {
  // ... existing fields

  // Your additions
  onboardingCompleted Boolean  @default(false)
  timezone            String?
  bio                 String?
}

After adding fields, run pnpm db:push in development or pnpm db:migrate for production.


Relations overview

User
 ├── Session[]          (active sessions)
 ├── Account[]          (OAuth + password accounts)
 ├── Passkey[]          (WebAuthn credentials)
 ├── Subscription?      (one Stripe subscription per user)
 └── OrganizationMember[] (org memberships)

Organization
 ├── OrganizationMember[]
 └── OrganizationInvite[]