Prisma Relations Pattern
Model one-to-one, one-to-many, many-to-many, and self-relations with @relation in Prisma
When to Use
- Adding foreign key relationships between Prisma models
- Modeling one-to-one, one-to-many, or many-to-many associations
- Creating self-referential relations (e.g., manager/employee, parent/child)
- Resolving ambiguous relations when two models have multiple connections
Instructions
- One-to-many — place the scalar foreign key and
@relationon the "many" side. The "one" side gets an array field:
model User {
id String @id @default(cuid())
posts Post[]
}
model Post {
id String @id @default(cuid())
author User @relation(fields: [authorId], references: [id])
authorId String
}
- One-to-one — identical to one-to-many but the relation field is singular on both sides. Add
@uniqueto the foreign key:
model User {
id String @id @default(cuid())
profile Profile?
}
model Profile {
id String @id @default(cuid())
user User @relation(fields: [userId], references: [id])
userId String @unique
}
- Many-to-many (implicit) — use array fields on both sides. Prisma creates the join table automatically:
model Post {
id String @id @default(cuid())
tags Tag[]
}
model Tag {
id String @id @default(cuid())
posts Post[]
}
- Many-to-many (explicit) — create an explicit join model when you need extra fields on the relationship:
model PostTag {
post Post @relation(fields: [postId], references: [id])
postId String
tag Tag @relation(fields: [tagId], references: [id])
tagId String
assignedAt DateTime @default(now())
@@id([postId, tagId])
}
- Self-relations — reference the same model. Use named
@relationto disambiguate:
model Employee {
id String @id @default(cuid())
manager Employee? @relation("ManagerReports", fields: [managerId], references: [id])
managerId String?
reports Employee[] @relation("ManagerReports")
}
- Disambiguate multiple relations between the same two models using the relation name string:
model User {
id String @id @default(cuid())
writtenPosts Post[] @relation("Author")
editedPosts Post[] @relation("Editor")
}
model Post {
id String @id @default(cuid())
author User @relation("Author", fields: [authorId], references: [id])
authorId String
editor User? @relation("Editor", fields: [editorId], references: [id])
editorId String?
}
- Referential actions — set
onDeleteandonUpdatebehavior:
author User @relation(fields: [authorId], references: [id], onDelete: Cascade, onUpdate: Cascade)
Options: Cascade, Restrict, NoAction, SetNull, SetDefault.
- Always add
@@index([foreignKeyField])on relation scalar fields for query performance.
Details
Prisma relations are defined at the Prisma schema level and map to foreign keys in the database. The @relation attribute is required on the side that stores the foreign key (the scalar field side).
Implicit vs explicit many-to-many: Implicit join tables follow the naming convention _ModelAToModelB (alphabetical). You cannot query the join table directly or add columns to it. Switch to explicit if you ever need metadata on the relationship.
Referential integrity modes:
foreignKeys(default for relational databases) — enforced by the databaseprisma— enforced by Prisma Client at the application level, required for databases that do not support foreign keys (e.g., PlanetScale with Vitess)
Cascade gotchas:
onDelete: Cascadeon a required relation means deleting a parent deletes all children — this is often not what you want for audit-sensitive dataonDelete: SetNullrequires the foreign key field to be optional (String?)- The default referential action varies by provider — PostgreSQL defaults to
NoAction, which throws on violation
Performance considerations:
- Every
includeon a relation triggers an additional SQL query (not a JOIN). For deeply nested includes, consider using raw queries with explicit JOINs - Implicit many-to-many creates an unindexed join table — add indexes manually via a migration if query performance degrades
Source
https://prisma.io/docs/orm/prisma-schema/data-model/relations
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.