Convert SQL Junction Tables to Prisma Many-to-Many Relations
Learn how SQL junction tables with composite primary keys convert to Prisma implicit or explicit many-to-many relations. Covers both patterns and when to choose each.
Detailed Explanation
Many-to-Many Relations
SQL models many-to-many relationships via a junction (join) table with two foreign keys. Prisma supports both implicit many-to-many (no junction model) and explicit many-to-many (with a junction model).
Example SQL
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL
);
CREATE TABLE tags (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL UNIQUE
);
CREATE TABLE article_tags (
article_id INTEGER NOT NULL,
tag_id INTEGER NOT NULL,
PRIMARY KEY (article_id, tag_id),
FOREIGN KEY (article_id) REFERENCES articles(id) ON DELETE CASCADE,
FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
);
Implicit Many-to-Many (Simple Junction)
model Article {
id Int @id @default(autoincrement())
title String
tags Tag[]
@@map("articles")
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
articles Article[]
@@map("tags")
}
Prisma manages the junction table automatically. The converter uses this pattern when the junction table has only the two foreign key columns and a composite primary key, with no extra data columns.
Explicit Many-to-Many (Junction with Extra Data)
CREATE TABLE enrollments (
student_id INTEGER NOT NULL,
course_id INTEGER NOT NULL,
enrolled_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
grade CHAR(2),
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES students(id),
FOREIGN KEY (course_id) REFERENCES courses(id)
);
model Student {
id Int @id @default(autoincrement())
enrollments Enrollment[]
@@map("students")
}
model Course {
id Int @id @default(autoincrement())
enrollments Enrollment[]
@@map("courses")
}
model Enrollment {
studentId Int @map("student_id")
courseId Int @map("course_id")
enrolledAt DateTime @default(now()) @map("enrolled_at")
grade String? @db.Char(2)
student Student @relation(fields: [studentId], references: [id])
course Course @relation(fields: [courseId], references: [id])
@@id([studentId, courseId])
@@map("enrollments")
}
Choosing Implicit vs Explicit
| Criterion | Implicit | Explicit |
|---|---|---|
| Junction has only FK columns | Yes | No |
| Extra fields on the relationship | Not possible | Supported |
| Prisma manages junction table | Automatically | You manage it |
| Query the junction directly | Not possible | Yes |
Converter Detection Logic
- Table has exactly two foreign key columns forming a composite PK: implicit candidate.
- If the table has additional non-FK columns (timestamps, metadata): explicit relation.
- If either FK references the same table (self-referencing M:N): always explicit.
Migration Note
When converting from SQL to Prisma's implicit M:N, Prisma expects the junction table to be named _ArticleToTag (alphabetical order, prefixed with underscore). The converter handles renaming or generates a migration step.
Use Case
You have both simple tag-assignment junction tables and enrollment tables with extra metadata. The converter determines whether to use Prisma implicit many-to-many or explicit junction models based on the junction table structure.
Try It — SQL to Prisma Schema
Related Topics
Convert SQL Foreign Keys to Prisma One-to-Many Relations
Relations
Convert SQL One-to-One Foreign Keys to Prisma Relations
Relations
Map SQL Primary Key Strategies to Prisma @id
Basic Models
Convert SQL UNIQUE Constraints to Prisma @unique and @@unique
Advanced Features
Convert an E-Commerce SQL Schema to Prisma
Real-World Schemas