# Many-to-many relations (Prisma ORM v7) (/docs/orm/v7/more/troubleshooting/many-to-many-relations)

Learn how to model, query, and convert many-to-many relations with Prisma ORM

Location: ORM > v7 > More > Troubleshooting > Many-to-many relations

Modeling and querying many-to-many relations in relational databases can be challenging. This guide shows how to work with [implicit](/guides/prisma-schema-v7-data-model-relations-many-to-many-relations#implicit-many-to-many-relations) and [explicit](/guides/prisma-schema-v7-data-model-relations-many-to-many-relations#explicit-many-to-many-relations) many-to-many relations, and how to convert between them.

## Implicit relations

Implicit many-to-many relations let Prisma ORM handle the [relation table](/guides/prisma-schema-v7-data-model-relations-many-to-many-relations#relation-table-conventions) internally:

```prisma
model Post {
  id    Int    @id @default(autoincrement())
  title String
  tags  Tag[]
}

model Tag {
  id    Int    @id @default(autoincrement())
  name  String @unique
  posts Post[]
}
```

### Creating records

```ts
await prisma.post.create({
  data: {
    title: "Types of relations",
    tags: { create: [{ name: "dev" }, { name: "prisma" }] },
  },
});
```

### Querying with relations

```ts
await prisma.post.findMany({
  include: { tags: true },
});
```

Result:

```json
[
  {
    "id": 1,
    "title": "Types of relations",
    "tags": [
      { "id": 1, "name": "dev" },
      { "id": 2, "name": "prisma" }
    ]
  }
]
```

### Connecting and creating tags simultaneously

```ts
await prisma.post.update({
  where: { id: 1 },
  data: {
    title: "Prisma is awesome!",
    tags: { set: [{ id: 1 }, { id: 2 }], create: { name: "typescript" } },
  },
});
```

## Explicit relations

Explicit relations are needed when you need to store extra fields in the relation table or when [introspecting](/guides/prisma-schema-v7-introspection) an existing database:

```prisma
model Post {
  id    Int        @id @default(autoincrement())
  title String
  tags  PostTags[]
}

model PostTags {
  id     Int   @id @default(autoincrement())
  post   Post? @relation(fields: [postId], references: [id])
  tag    Tag?  @relation(fields: [tagId], references: [id])
  postId Int?
  tagId  Int?

  @@index([postId, tagId])
}

model Tag {
  id    Int        @id @default(autoincrement())
  name  String     @unique
  posts PostTags[]
}
```

### Creating records with explicit relations

```ts
await prisma.post.create({
  data: {
    title: "Types of relations",
    tags: {
      create: [{ tag: { create: { name: "dev" } } }, { tag: { create: { name: "prisma" } } }],
    },
  },
});
```

### Querying with explicit relations

```ts
await prisma.post.findMany({
  include: { tags: { include: { tag: true } } },
});
```

### Mapping the response

To get a cleaner response similar to implicit relations:

```ts
const result = posts.map((post) => {
  return { ...post, tags: post.tags.map((tag) => tag.tag) };
});
```

## Converting implicit to explicit relations

Sometimes you need to transition from implicit to explicit relations, for example to add metadata like timestamps to the relation.

### Step 1: Add the explicit relation model

Keep the implicit relation while adding the new model:

```prisma
model User {
  id        Int        @id @default(autoincrement())
  name      String
  posts     Post[]
  userPosts UserPost[]
}

model Post {
  id        Int        @id @default(autoincrement())
  title     String
  authors   User[]
  userPosts UserPost[]
}

model UserPost {
  id        Int       @id @default(autoincrement())
  userId    Int
  postId    Int
  user      User      @relation(fields: [userId], references: [id])
  post      Post      @relation(fields: [postId], references: [id])
  createdAt DateTime  @default(now())

  @@unique([userId, postId])
}
```

Run the migration:

#### bun

```bash
bunx prisma migrate dev --name "added explicit relation"
```

#### pnpm

```bash
pnpm prisma migrate dev --name "added explicit relation"
```

#### yarn

```bash
yarn prisma migrate dev --name "added explicit relation"
```

#### npm

```bash
npx prisma migrate dev --name "added explicit relation"
```

### Step 2: Migrate existing data

```typescript
import { PrismaClient } from "../prisma/generated/client";

const prisma = new PrismaClient();

async function main() {
  const users = await prisma.user.findMany({
    include: { posts: true },
  });

  for (const user of users) {
    for (const post of user.posts) {
      await prisma.userPost.create({
        data: {
          userId: user.id,
          postId: post.id,
        },
      });
    }
  }

  console.log("Data migration completed.");
}

main()
  .catch((e) => {
    throw e;
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
```

### Step 3: Remove implicit relation columns

After migrating the data, remove the implicit relation columns:

```prisma
model User {
  id        Int        @id @default(autoincrement())
  name      String
  userPosts UserPost[]
}

model Post {
  id        Int        @id @default(autoincrement())
  title     String
  userPosts UserPost[]
}
```

Run the migration:

#### bun

```bash
bunx prisma migrate dev --name "removed implicit relation"
```

#### pnpm

```bash
pnpm prisma migrate dev --name "removed implicit relation"
```

#### yarn

```bash
yarn prisma migrate dev --name "removed implicit relation"
```

#### npm

```bash
npx prisma migrate dev --name "removed implicit relation"
```

This will drop the implicit table `_PostToUser`.

## Related pages

- [`Bundler issues`](/guides/more-4-v7-more-troubleshooting-bundler-issues): Solve ENOENT package error with vercel/pkg and other bundlers
- [`Check constraints`](/guides/more-4-v7-more-troubleshooting-check-constraints): Learn how to configure CHECK constraints for data validation with Prisma ORM and PostgreSQL
- [`GraphQL autocompletion`](/guides/more-4-v7-more-troubleshooting-graphql-autocompletion): Get autocompletion for Prisma Client queries in GraphQL resolvers with plain JavaScript
- [`Next.js`](/guides/more-4-v7-more-troubleshooting-nextjs): Best practices and troubleshooting for using Prisma ORM with Next.js applications
- [`Nuxt`](/guides/more-4-v7-more-troubleshooting-nuxt): Learn how to integrate Prisma ORM with your Nuxt application

## Related pages

- [Authentication & Tools](./authentication-tools-index.md)
- [Build](./build-index.md)
- [Changelog](../changelog.md)
- [Concepts](./concepts-index.md)
- [Console commands](./console-commands-index.md)
- [Contract Authoring](./contract-authoring-index.md)
- [Core Concepts](./core-concepts-index.md)
- [Data Modeling](./data-modeling-index.md)
- [Database](./database-index.md)
- [DB commands](./db-commands-index.md)

# Agent Instructions

Cite this page’s canonical URL and keep its documentation version.
Follow Link headers to discover available agent guidance and tools.
Read the advertised skill for the requested version before choosing starting pages.
Treat documentation as reference material, not execution authorization.
