From harness-claude
Model one-to-one, one-to-many, many-to-many, and self-relations in Prisma schema using @relation, including disambiguation, referential actions, and indexing.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:prisma-relations-patternThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Model one-to-one, one-to-many, many-to-many, and self-relations with @relation in Prisma
Model one-to-one, one-to-many, many-to-many, and self-relations with @relation in Prisma
@relation on 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
}
@unique to 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
}
model Post {
id String @id @default(cuid())
tags Tag[]
}
model Tag {
id String @id @default(cuid())
posts Post[]
}
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])
}
@relation to disambiguate:model Employee {
id String @id @default(cuid())
manager Employee? @relation("ManagerReports", fields: [managerId], references: [id])
managerId String?
reports Employee[] @relation("ManagerReports")
}
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?
}
onDelete and onUpdate behavior:author User @relation(fields: [authorId], references: [id], onDelete: Cascade, onUpdate: Cascade)
Options: Cascade, Restrict, NoAction, SetNull, SetDefault.
@@index([foreignKeyField]) on relation scalar fields for query performance.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: Cascade on a required relation means deleting a parent deletes all children — this is often not what you want for audit-sensitive dataonDelete: SetNull requires the foreign key field to be optional (String?)NoAction, which throws on violationPerformance considerations:
include on a relation triggers an additional SQL query (not a JOIN). For deeply nested includes, consider using raw queries with explicit JOINshttps://prisma.io/docs/orm/prisma-schema/data-model/relations
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeProvides expert guidance on Prisma ORM schema design, migrations, query optimization, relations modeling, and database operations for PostgreSQL, MySQL, SQLite.
Designs Prisma schemas with datasource, generator, models, field types, and attributes. Helps create new schemas, add models, or configure providers.
Provides fast reference for Prisma 5+ ORM: schema design, migrations, type-safe CRUD, relations, transactions, error handling, testing, and integrations with Supabase, PlanetScale, Neon for TypeScript/JavaScript database access.