> Model one-to-one, one-to-many, many-to-many, and self-relations with @relation in Prisma
Scanned 9/11/2026
Install to Claude Code
npx -y skills add Intense-Visions/harness-engineering --skill prisma-relations-pattern --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Prisma Relations Pattern?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/intense-visions-prisma-relations-pattern-5e36b2ac)More formats (shields.io, HTML) on the badges page.
# 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
1. **One-to-many** — place the scalar foreign key and `@relation` on the "many" side. The "one" side gets an array field:
```prisma
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
}
```
2. **One-to-one** — identical to one-to-many but the relation field is singular on both sides. Add `@unique` to the foreign key:
```prisma
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
}
```
3. **Many-to-many (implicit)** — use array fields on both sides. Prisma creates the join table automatically:
```prisma
model Post {
id String @id @default(cuid())
tags Tag[]
}
model Tag {
id String @id @default(cuid())
posts Post[]
}
```
4. **Many-to-many (explicit)** — create an explicit join model when you need extra fields on the relationship:
```prisma
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])
}
```
5. **Self-relations** — reference the same model. Use named `@relation` to disambiguate:
```prisma
model Employee {
id String @id @default(cuid())
manager Employee? @relation("ManagerReports", fields: [managerId], references: [id])
managerId String?
reports Employee[] @relation("ManagerReports")
}
```
6. **Disambiguate multiple relations** between the same two models using the relation name string:
```prisma
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?
}
```
7. **Referential actions** — set `onDelete` and `onUpdate` behavior:
```prisma
author User @relation(fields: [authorId], references: [id], onDelete: Cascade, onUpdate: Cascade)
```
Options: `Cascade`, `Restrict`, `NoAction`, `SetNull`, `SetDefault`.
8. 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 database
- `prisma` — 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: Cascade` on a required relation means deleting a parent deletes all children — this is often not what you want for audit-sensitive data
- `onDelete: SetNull` requires 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 `include` on 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
1. Read the instructions and examples in this document.
2. Apply the patterns to your implementation, adapting to your specific context.
3. 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.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!