---
title: "Prisma Schema"
slug: "prisma-schema"
category: "backend"
tags: ["backend", "prisma", "schema", "orm", "typescript", "postgres", "modeling"]
status: "stable"
last_updated: 2026-05-29
summary: "Model datasources, generators, and models in schema.prisma with the Prisma 7 prisma-client generator, field attributes, and relation modes."
related:
  [
    "[[backend/prisma]]",
    "[[backend/postgres]]",
    "[[backend/migrations]]",
    "[[backend/prisma-migrations]]",
    "[[backend/prisma-client]]",
    "[[backend/prisma-driver-adapters]]",
    "[[comparisons/prisma-vs-drizzle]]",
    "[[backend/prisma-transactions]]",
  ]
---

## Overview

`schema.prisma` is the single source of truth for your database shape. It defines the datasource (which database to connect to), the generator (what client to emit), and every model (table), field (column), and relation (foreign key). Prisma reads this file to generate migrations and the typed client. Treat it the way you treat compiled code: the schema is the contract; everything else is derived.

## Declare one datasource and pin the provider

A `schema.prisma` file supports exactly one `datasource` block.

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

Pin the provider to `postgresql`, `mysql`, or `sqlite`. Do not switch providers without regenerating all migrations from scratch. Provider determines which SQL dialect Prisma emits and which native types are available. Use `env()` for the URL so the secret never lands in source control. See [[backend/postgres]] for connection string format.

## Configure the generator for your runtime

The `generator` block controls what Prisma emits after `prisma generate`.

```prisma
generator client {
  provider = "prisma-client"
  output   = "../src/generated/prisma"
}
```

- Use `prisma-client` for Node and Bun. It is the Rust-free default in Prisma 7 and replaces the legacy `prisma-client-js` generator.
- `output` is required for `prisma-client` and must point inside your source tree (not `node_modules`). Commit nothing under it; add the directory to `.gitignore`.
- Do not list `driverAdapters` under `previewFeatures`. Driver adapters are GA in Prisma 7 and used by default; see [[backend/prisma-driver-adapters]].
- Add `previewFeatures` only for a capability still behind a flag. See [[backend/prisma-client]] for the singleton pattern and [[backend/prisma-v6-to-v7-upgrade]] for the generator swap.

## Give every model an `@id` field

Prisma requires exactly one `@id` or `@@id` per model.

```prisma
model Product {
  id        String   @id @default(cuid())
  sku       String   @unique
  price     Int
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
```

- Prefer `cuid()` or `uuid(7)` over `autoincrement()` when you distribute writes across multiple databases or replicas. Time-ordered v7 UUIDs (`uuid(7)`, backed by Postgres 18's native `uuidv7()`) keep inserts index-friendly; random v4 UUIDs scatter writes across the B-tree.
- Use `@updatedAt` for timestamps Prisma should maintain automatically. It sets the field to `now()` on every `update` call.
- Use `@default(now())` for `createdAt`. Never compute it in application code.

## Declare `@unique` and `@@unique` for natural keys

Unique constraints live in the schema, not in a migration file you wrote by hand.

```prisma
model User {
  id    String @id @default(cuid())
  email String @unique

  @@unique([tenantId, slug])
}
```

- Put `@unique` on single-field natural keys (email, slug, external ID).
- Use `@@unique([a, b])` for composite uniqueness. Prisma generates the constraint name automatically.
- Use `@@index([col])` for columns you filter or sort on but do not need unique. See [[backend/postgres]] for index sizing rules.

## Define relations explicitly on both sides

Prisma requires that you declare the full relation on at least one model.

```prisma
model Order {
  id     String @id @default(cuid())
  userId String
  user   User   @relation(fields: [userId], references: [id], onDelete: Cascade)
  items  OrderItem[]
}

model User {
  id     String  @id @default(cuid())
  orders Order[]
}
```

- Specify `fields` (the foreign key column), `references` (the referenced column), and `onDelete` behavior.
- `Cascade` deletes children when the parent is deleted. `Restrict` (the Prisma default) blocks the parent deletion. Choose explicitly rather than relying on defaults.
- For self-relations, declare both the scalar and the relation field on the same model.

## Set `relationMode` when your database does not enforce foreign keys

Some hosted databases (PlanetScale, older MySQL, read replicas) do not enforce foreign-key constraints at the engine level.

```prisma
datasource db {
  provider     = "mysql"
  url          = env("DATABASE_URL")
  relationMode = "prisma"
}
```

- `"prisma"` emulates foreign-key checks in the Prisma query layer instead of at the DB level.
- `"foreignKeys"` (default) relies on the database to enforce constraints. Use this with [[backend/postgres]].
- Mixing `"prisma"` mode with Postgres is legal but redundant. Pick one enforcement layer.

## Map Prisma scalar types to native database types

Prisma provides cross-DB scalar types. Use `@db.*` native type modifiers when the default mapping is too broad.

```prisma
model Article {
  id      String @id @default(cuid())
  title   String @db.VarChar(255)
  body    String @db.Text
  score   Float  @db.DoublePrecision
  meta    Json
  enabled Boolean @default(true)
}
```

- `String` maps to `TEXT` by default in Postgres. Use `@db.VarChar(n)` when length matters for indexes or storage.
- `Int` maps to `INTEGER`. Use `@db.BigInt` for columns that may exceed 2 billion.
- `Json` maps to `JSONB` in Postgres. Queries on `Json` fields require `$queryRaw`. See [[backend/prisma-raw-queries]].
- After changing native type modifiers, run `prisma migrate dev` to emit the correct `ALTER TABLE`. See [[backend/prisma-migrations]].

## Related

- [[backend/prisma]]
- [[backend/postgres]]
- [[backend/migrations]]
- [[backend/prisma-migrations]]
- [[backend/prisma-client]]
- [[backend/prisma-transactions]]
- [[comparisons/prisma-vs-drizzle]]
