Overview
schema.prisma defines the models, relations, and generator that Prisma turns into migrations and the typed client. In Prisma 7 it no longer holds the connection URL. Treat the schema as the contract and everything else as derived from it.
Declare the provider only; put the URL in prisma.config.ts
Prisma 7 moved url, directUrl, and shadowDatabaseUrl out of the schema and into prisma.config.ts. The datasource block names the provider and, optionally, relationMode.
datasource db {
provider = "postgresql"
}Do not switch providers without regenerating migrations; the provider selects the SQL dialect and the available native types. Keep the URL in an environment variable loaded by the config file; see prisma.
Use the prisma-client generator and set output
generator client {
provider = "prisma-client"
output = "../src/generated/prisma"
}prisma-clientreplaces the deprecatedprisma-client-js.outputis required and must sit in your source tree, notnode_modules.- Add the output directory to
.gitignoreand regenerate inpostinstall; see prisma-client. - Do not list
driverAdaptersinpreviewFeatures; adapters are standard in Prisma 7. AddpreviewFeaturesonly for a capability that is still flagged. - A schema can be split across files. Point
schemainprisma.config.tsat a folder.
Give every model an id and choose its generator deliberately
Prisma requires one @id or @@id per model.
model Product {
id String @id @default(uuid(7))
sku String @unique
price Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}cuid(),uuid(), anduuid(7)are generated by Prisma Client, not by the database. Preferuuid(7)(time-ordered) overuuid()for index locality. To let Postgres 18 generate it, use@default(dbgenerated("uuidv7()")) @db.Uuid; see postgres.- Use
autoincrement()when one database assigns ids. @updatedAtis maintained by Prisma on eachupdate.@default(now())setscreatedAt; do not compute it in application code.
Put uniqueness and indexes in the schema
@uniquefor single-field natural keys (email, slug, external id);@@unique([a, b])for composite keys.@@index([col])for columns you filter or sort on. Match each index to a real query; see postgres-indexes.- Indexes and constraints Prisma cannot express belong in a hand-edited migration; see prisma-migrations.
Declare relations on both sides with explicit onDelete
model Order {
id String @id @default(uuid(7))
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
items OrderItem[]
}
model User {
id String @id @default(uuid(7))
orders Order[]
}Specify fields, references, and onDelete. Defaults differ between required and optional relations, so choose Cascade, Restrict, or SetNull per relation instead of inheriting them.
Set relationMode only when the database does not enforce foreign keys
The default, foreignKeys, relies on the database. Use relationMode = "prisma" only for a database without foreign key support; Prisma then emulates the checks in its query layer and does not create indexes on relation columns, so add @@index on every foreign key column yourself. Do not combine it with Postgres, which already enforces foreign keys.
Map to native types when defaults are too loose
Stringmaps totexton Postgres. Use@db.VarChar(n)when length matters.Intmaps tointeger. UseBigIntfor values that may pass 2 billion.Jsonmaps tojsonb. Prisma filters Json fields withpath,equals,string_contains, andarray_contains; Postgres paths are arrays such as["petName"]. Use prisma-raw-queries forjsonb_path_queryand operators Prisma lacks, and see postgres-jsonb.- Run
prisma migrate devafter changing native types so theALTER TABLEis generated.