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[]Auth, billing, orgs, and emails — all wired up. Clone and deploy in minutes.
Get launch.now