Database Schema

TurboStack uses Prisma ORM with PostgreSQL for type-safe database operations.

Models

User

The main user model with authentication fields.
model User {
  id            String    @id @default(cuid())
  email         String    @unique
  name          String?
  password      String
  role          Role      @default(USER)
  emailVerified DateTime?
  avatar        String?
  createdAt     DateTime  @default(now())
  updatedAt     DateTime  @updatedAt

  // Relations
  sessions              Session[]
  verificationTokens    VerificationToken[]
  passwordResetTokens   PasswordResetToken[]
  purchases             Purchase[]
  subscriptions         Subscription[]
}

enum Role {
  USER
  ADMIN
}
FieldTypeDescription
idStringCUID primary key
emailStringUnique email address
passwordStringArgon2 hashed password
roleEnumUSER or ADMIN
emailVerifiedDateTime?When email was verified
Active user sessions for authentication.
model Session {
  id        String   @id @default(cuid())
  token     String   @unique
  userId    String
  expiresAt DateTime
  createdAt DateTime @default(now())

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

  @@index([userId])
  @@index([token])
}
Email verification tokens sent to users.
model VerificationToken {
  id        String   @id @default(cuid())
  token     String   @unique
  userId    String
  expiresAt DateTime
  createdAt DateTime @default(now())

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

  @@index([token])
  @@index([userId])
}
One-time purchases via Polar.sh.
model Purchase {
  id           String   @id @default(cuid())
  userId       String
  productId    String
  polarOrderId String   @unique
  amount       Int
  currency     String   @default("USD")
  createdAt    DateTime @default(now())

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

  @@index([userId])
  @@index([polarOrderId])
}
Recurring subscriptions via Polar.sh.
model Subscription {
  id                  String    @id @default(cuid())
  userId              String
  polarSubscriptionId String    @unique
  status              String
  planId              String
  currentPeriodEnd    DateTime
  canceledAt          DateTime?
  createdAt           DateTime  @default(now())
  updatedAt           DateTime  @updatedAt

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

  @@index([userId])
  @@index([polarSubscriptionId])
}

Common Queries

import { prisma } from "@repo/database";

// Create a user
const user = await prisma.user.create({
  data: {
    email: "user@example.com",
    name: "John Doe",
    password: hashedPassword,
  },
});

// Create with relation
const session = await prisma.session.create({
  data: {
    token: sessionToken,
    userId: user.id,
    expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
  },
});

Database Commands

Push Schema

bun run db:push
Push changes without migrations (dev)

Generate Client

bun run db:generate
Regenerate Prisma client

Run Migrations

bun run db:migrate
Create and apply migrations

Open Studio

bun run db:studio
Visual database browser

Adding New Models

1

Edit Schema

Add your model to packages/database/prisma/schema.prisma:
model Product {
  id          String   @id @default(cuid())
  name        String
  description String?
  price       Int
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt
}
2

Push or Migrate

# Development (quick sync)
bun run db:push

# Production (with migration history)
bun run db:migrate
3

Use in Code

import { prisma } from "@repo/database";

const products = await prisma.product.findMany();
Use bun run db:studio to visually explore and edit your database at localhost:5555.