Skip to main content
Prisma Documentation Docs

Search documentation

Type to search this documentation.

On this pageOverview

Relation queries (Prisma ORM v6) (/docs/orm/v6/prisma-client/queries/relation-queries)

For the complete Prisma documentation index, see llms.txt. A markdown version of any docs page is available by appending .md to its URL.

Prisma Client provides convenient queries for working with relations, such as a fluent API, nested writes (transactions), nested reads and relation filters.

Location: ORM > v6 > Prisma Client > Queries > Relation queries

A key feature of Prisma Client is the ability to query relations between two or more models. Relation queries include:

Prisma Client also has a fluent API for traversing relations.

Nested reads allow you to read related data from multiple tables in your database - such as a user and that user's posts. You can:

  • Use include to include related records, such as a user's posts or profile, in the query response.
  • Use a nested select to include specific fields from a related record. You can also nest select inside an include.

Since version 5.8.0, you can decide on a per-query-level how you want Prisma Client to execute a relation query (i.e. what load strategy should be applied) via the relationLoadStrategy option for PostgreSQL databases.

Since version 5.10.0, this feature is also available for MySQL.

Because the relationLoadStrategy option is currently in Preview, you need to enable it via the relationJoins preview feature flag in your Prisma schema file:

schema.prisma
generator client {
  provider        = "prisma-client"
  output          = "./generated"
  previewFeatures = ["relationJoins"]
}

After adding this flag, you need to run prisma generate again to re-generate Prisma Client. The relationJoins feature is currently available on PostgreSQL, CockroachDB and MySQL.

Prisma Client supports two load strategies for relations:

  • join (default): Uses a database-level LATERAL JOIN (PostgreSQL) or correlated subqueries (MySQL) and fetches all data with a single query to the database.
  • query: Sends multiple queries to the database (one per table) and joins them on the application level.

Another important difference between these two options is that the join strategy uses JSON aggregation on the database level. That means that it creates the JSON structures returned by Prisma Client already in the database which saves computation resources on the application level.

Note: Once relationLoadStrategy moves from Preview into General Availability, join will universally become the default for all relation queries.

You can use the relationLoadStrategy option on the top-level in any query that supports include or select.

Here is an example with include:

TypeScript
const users = await prisma.user.findMany({
  relationLoadStrategy: "join", // or 'query'
  include: {
    posts: true,
  },
});

And here is another example with select:

TypeScript
const users = await prisma.user.findMany({
  relationLoadStrategy: "join", // or 'query'
  select: {
    posts: true,
  },
});
  • The join strategy (default) will be more effective in most scenarios. On PostgreSQL, it uses a combination of LATERAL JOINs and JSON aggregation to reduce redundancy in result sets and delegate the work of transforming the query results into the expected JSON structures on the database server. On MySQL, it uses correlated subqueries to fetch the results with a single query.
  • There may be edge cases where query could be more performant depending on the characteristics of the dataset and query. We recommend that you profile your database queries to identify these situations.
  • Use query if you want to save resources on the database server and do heavy-lifting of merging and transforming data in the application server which might be easier to scale.

The following example returns a single user and that user's posts:

TypeScript
const user = await prisma.user.findFirst({
  include: {
    posts: true,
  },
});
no-copy
{
  id: 19,
  name: null,
  email: 'emma@prisma.io',
  profileViews: 0,
  role: 'USER',
  coinflips: [],
  posts: [
    {
      id: 20,
      title: 'My first post',
      published: true,
      authorId: 19,
      comments: null,
      views: 0,
      likes: 0
    },
    {
      id: 21,
      title: 'How to make cookies',
      published: true,
      authorId: 19,
      comments: null,
      views: 0,
      likes: 0
    }
  ]
}

The following example returns a post and its author:

TypeScript
const post = await prisma.post.findFirst({
  include: {
    author: true,
  },
});
no-copy
{
  id: 17,
  title: 'How to make cookies',
  published: true,
  authorId: 16,
  comments: null,
  views: 0,
  likes: 0,
  author: {
    id: 16,
    name: null,
    email: 'orla@prisma.io',
    profileViews: 0,
    role: 'USER',
    coinflips: [],
  },
}

You can nest include options to include relations of relations. The following example returns a user's posts, and each post's categories:

TypeScript
const user = await prisma.user.findFirst({
  include: {
    posts: {
      include: {
        categories: true,
      },
    },
  },
});
no-copy
{
    "id": 40,
    "name": "Yvette",
    "email": "yvette@prisma.io",
    "profileViews": 0,
    "role": "USER",
    "coinflips": [],
    "testing": [],
    "city": null,
    "country": "Sweden",
    "posts": [
        {
            "id": 66,
            "title": "How to make an omelette",
            "published": true,
            "authorId": 40,
            "comments": null,
            "views": 0,
            "likes": 0,
            "categories": [
                {
                    "id": 3,
                    "name": "Easy cooking"
                }
            ]
        },
        {
            "id": 67,
            "title": "How to eat an omelette",
            "published": true,
            "authorId": 40,
            "comments": null,
            "views": 0,
            "likes": 0,
            "categories": []
        }
    ]
}

Select specific fields of included relations

Section titled “Select specific fields of included relations”

You can use a nested select to choose a subset of fields of relations to return. For example, the following query returns the user's name and the title of each related post:

TypeScript
const user = await prisma.user.findFirst({
  select: {
    name: true,
    posts: {
      select: {
        title: true,
      },
    },
  },
});
no-copy
{
  name: "Elsa",
  posts: [ { title: 'My first post' }, { title: 'How to make cookies' } ]
}

You can also nest a select inside an include - the following example returns all User fields and the title field of each post:

TypeScript
const user = await prisma.user.findFirst({
  include: {
    posts: {
      select: {
        title: true,
      },
    },
  },
});
no-copy
{
  "id": 1,
  "name": null,
  "email": "martina@prisma.io",
  "profileViews": 0,
  "role": "USER",
  "coinflips": [],
  "posts": [
    { "title": "How to grow salad" },
    { "title": "How to ride a horse" }
  ]
}

Note that you cannot use select and include on the same level. This means that if you choose to include a user's post and select each post's title, you cannot select only the users' email:

TypeScript
// The following query returns an exceptionconst user = await prisma.user.findFirst({  select: { // This won't work!    email:  true  }  include: { // This won't work!    posts: {      select: {        title: true      }    }  },})
no-copy
Invalid `prisma.user.findUnique()` invocation:

{
  where: {
    id: 19
  },
  select: {
  ~~~~~~
    email: true
  },
  include: {
  ~~~~~~~
    posts: {
      select: {
        title: true
      }
    }
  }
}

Please either use `include` or `select`, but not both at the same time.

Instead, use nested select options:

TypeScript
const user = await prisma.user.findFirst({
  select: {
    // This will work!
    email: true,
    posts: {
      select: {
        title: true,
      },
    },
  },
});

In 3.0.1 and later, you can include or select a count of relations alongside fields - for example, a user's post count.

TypeScript
const relationCount = await prisma.user.findMany({
  include: {
    _count: {
      select: { posts: true },
    },
  },
});
no-copy
{ id: 1, _count: { posts: 3 } },
{ id: 2, _count: { posts: 2 } },
{ id: 3, _count: { posts: 2 } },
{ id: 4, _count: { posts: 0 } },
{ id: 5, _count: { posts: 0 } }

When you use select or include to return a subset of the related data, you can filter and sort the list of relations inside the select or include.

For example, the following query returns list of titles of the unpublished posts associated with the user:

TypeScript
const result = await prisma.user.findFirst({
  select: {
    posts: {
      where: {
        published: false,
      },
      orderBy: {
        title: "asc",
      },
      select: {
        title: true,
      },
    },
  },
});

You can also write the same query using include as follows:

TypeScript
const result = await prisma.user.findFirst({
  include: {
    posts: {
      where: {
        published: false,
      },
      orderBy: {
        title: "asc",
      },
    },
  },
});

A nested write allows you to write relational data to your database in a single transaction.

Nested writes:

  • Provide transactional guarantees for creating, updating or deleting data across multiple tables in a single Prisma Client query. If any part of the query fails (for example, creating a user succeeds but creating posts fails), Prisma Client rolls back all changes.
  • Support any level of nesting supported by the data model.
  • Are available for relation fields when using the model's create or update query. The following section shows the nested write options that are available per query.

You can create a record and one or more related records at the same time. The following query creates a User record and two related Post records:

TypeScript
const result = await prisma.user.create({  data: {    email: "elsa@prisma.io",    name: "Elsa Prisma",    posts: {      create: [{ title: "How to make an omelette" }, { title: "How to eat an omelette" }],    },  },  include: {    posts: true, // Include all posts in the returned object  },});
no-copy
{
  id: 29,
  name: 'Elsa',
  email: 'elsa@prisma.io',
  profileViews: 0,
  role: 'USER',
  coinflips: [],
  posts: [
    {
      id: 22,
      title: 'How to make an omelette',
      published: true,
      authorId: 29,
      comments: null,
      views: 0,
      likes: 0
    },
    {
      id: 23,
      title: 'How to eat an omelette',
      published: true,
      authorId: 29,
      comments: null,
      views: 0,
      likes: 0
    }
  ]
}
Section titled “Create a single record and multiple related records”

There are two ways to create or update a single record and multiple related records - for example, a user with multiple posts:

In most cases, a nested create will be preferable unless the skipDuplicates query option is required. Here's a quick table describing the differences between the two options:

Feature create createMany Notes
Supports nesting additional relations ✔ ✘ * For example, you can create a user, several posts, and several comments per post in one query.
* You can manually set a foreign key in a has-one relation - for example: { authorId: 9}
Supports 1-n relations ✔ ✔ For example, you can create a user and multiple posts (one user has many posts)
Supports m-n relations ✔ ✘ For example, you can create a post and several categories (one post can have many categories, and one category can have many posts)
Supports skipping duplicate records ✘ ✔ Use skipDuplicates query option.

The following query uses nested create to create:

  • One user
  • Two posts
  • One post category

The example also uses a nested include to include all posts and post categories in the returned data.

TypeScript
const result = await prisma.user.create({  data: {    email: "yvette@prisma.io",    name: "Yvette",    posts: {      create: [        {          title: "How to make an omelette",          categories: {            create: {              name: "Easy cooking",            },          },        },        { title: "How to eat an omelette" },      ],    },  },  include: {    // Include posts    posts: {      include: {        categories: true, // Include post categories      },    },  },});
no-copy
{
    "id": 40,
    "name": "Yvette",
    "email": "yvette@prisma.io",
    "profileViews": 0,
    "role": "USER",
    "coinflips": [],
    "testing": [],
    "city": null,
    "country": "Sweden",
    "posts": [
        {
            "id": 66,
            "title": "How to make an omelette",
            "published": true,
            "authorId": 40,
            "comments": null,
            "views": 0,
            "likes": 0,
            "categories": [
                {
                    "id": 3,
                    "name": "Easy cooking"
                }
            ]
        },
        {
            "id": 67,
            "title": "How to eat an omelette",
            "published": true,
            "authorId": 40,
            "comments": null,
            "views": 0,
            "likes": 0,
            "categories": []
        }
    ]
}

Here's a visual representation of how a nested create operation can write to several tables in the database as once:

Diagram showing how a nested create operation writes to multiple database tables (User, Post, Category) in a single transaction.

The following query uses a nested createMany to create:

  • One user
  • Two posts

The example also uses a nested include to include all posts in the returned data.

TypeScript
const result = await prisma.user.create({  data: {    email: "saanvi@prisma.io",    posts: {      createMany: {        data: [{ title: "My first post" }, { title: "My second post" }],      },    },  },  include: {    posts: true,  },});
no-copy
{
    "id": 43,
    "name": null,
    "email": "saanvi@prisma.io",
    "profileViews": 0,
    "role": "USER",
    "coinflips": [],
    "testing": [],
    "city": null,
    "country": "India",
    "posts": [
        {
            "id": 70,
            "title": "My first post",
            "published": true,
            "authorId": 43,
            "comments": null,
            "views": 0,
            "likes": 0
        },
        {
            "id": 71,
            "title": "My second post",
            "published": true,
            "authorId": 43,
            "comments": null,
            "views": 0,
            "likes": 0
        }
    ]
}

Note that it is not possible to nest an additional create or createMany inside the highlighted query, which means that you cannot create a user, posts, and post categories at the same time.

As a workaround, you can send a query to create the records that will be connected first, and then create the actual records. For example:

TypeScript
const categories = await prisma.category.createManyAndReturn({
  data: [{ name: "Fun" }, { name: "Technology" }, { name: "Sports" }],
  select: {
    id: true,
  },
});

const posts = await prisma.post.createManyAndReturn({
  data: [
    {
      title: "Funniest moments in 2024",
      categoryId: categories.find((category) => category.name === "Fun")!.id,
    },
    {
      title: "Linux or macOS — what's better?",
      categoryId: categories.find((category) => category.name === "Technology")!.id,
    },
    {
      title: "Who will win the next soccer championship?",
      categoryId: categories.find((category) => category.name === "Sports")!.id,
    },
  ],
});

If you want to create all records in a single database query, consider using a $transaction or type-safe, raw SQL.

Section titled “Create multiple records and multiple related records”

You cannot access relations in a createMany() or createManyAndReturn() query, which means that you cannot create multiple users and multiple posts in a single nested write. The following is not possible:

TypeScript
const createMany = await prisma.user.createMany({  data: [    {      name: "Yewande",      email: "yewande@prisma.io",      posts: {        // Not possible to create posts!      },    },    {      name: "Noor",      email: "noor@prisma.io",      posts: {        // Not possible to create posts!      },    },  ],});

The following query creates (create ) a new User record and connects that record (connect ) to three existing posts:

TypeScript
const result = await prisma.user.create({  data: {    email: "vlad@prisma.io",    posts: {      connect: [{ id: 8 }, { id: 9 }, { id: 10 }],    },  },  include: {    posts: true, // Include all posts in the returned object  },});
no-copy
{
  id: 27,
  name: null,
  email: 'vlad@prisma.io',
  profileViews: 0,
  role: 'USER',
  coinflips: [],
  posts: [
    {
      id: 10,
      title: 'An existing post',
      published: true,
      authorId: 27,
      comments: {},
      views: 0,
      likes: 0
    }
  ]
}

Note: Prisma Client throws an exception if any of the post records cannot be found: connect: [{ id: 8 }, { id: 9 }, { id: 10 }]

You can connect an existing record to a new or existing user. The following query connects an existing post (id: 11) to an existing user (id: 9)

TypeScript
const result = await prisma.user.update({  where: {    id: 9,  },  data: {    posts: {      connect: {        id: 11,      },    },  },  include: {    posts: true,  },});

If a related record may or may not already exist, use connectOrCreate to connect the related record:

  • Connect a User with the email address viola@prisma.io or
  • Create a new User with the email address viola@prisma.io if the user does not already exist
TypeScript
const result = await prisma.post.create({  data: {    title: "How to make croissants",    author: {      connectOrCreate: {        where: {          email: "viola@prisma.io",        },        create: {          email: "viola@prisma.io",          name: "Viola",        },      },    },  },  include: {    author: true,  },});
no-copy
{
  id: 26,
  title: 'How to make croissants',
  published: true,
  authorId: 43,
  views: 0,
  likes: 0,
  author: {
    id: 43,
    name: 'Viola',
    email: 'viola@prisma.io',
    profileViews: 0,
    role: 'USER',
    coinflips: []
  }
}

To disconnect one out of a list of records (for example, a specific blog post) provide the ID or unique identifier of the record(s) to disconnect:

TypeScript
const result = await prisma.user.update({  where: {    id: 16,  },  data: {    posts: {      disconnect: [{ id: 12 }, { id: 19 }],    },  },  include: {    posts: true,  },});
no-copy
{
  id: 16,
  name: null,
  email: 'orla@prisma.io',
  profileViews: 0,
  role: 'USER',
  coinflips: [],
  posts: []
}

To disconnect one record (for example, a post's author), use disconnect: true:

TypeScript
const result = await prisma.post.update({  where: {    id: 23,  },  data: {    author: {      disconnect: true,    },  },  include: {    author: true,  },});
no-copy
{
  id: 23,
  title: 'How to eat an omelette',
  published: true,
  authorId: null,
  comments: null,
  views: 0,
  likes: 0,
  author: null
}

To disconnect all related records in a one-to-many relation (a user has many posts), set the relation to an empty list as shown:

TypeScript
const result = await prisma.user.update({  where: {    id: 16,  },  data: {    posts: {      set: [],    },  },  include: {    posts: true,  },});
no-copy
{
  id: 16,
  name: null,
  email: 'orla@prisma.io',
  profileViews: 0,
  role: 'USER',
  coinflips: [],
  posts: []
}

Delete all related Post records:

TypeScript
const result = await prisma.user.update({  where: {    id: 11,  },  data: {    posts: {      deleteMany: {},    },  },  include: {    posts: true,  },});

Update a user by deleting all unpublished posts:

TypeScript
const result = await prisma.user.update({  where: {    id: 11,  },  data: {    posts: {      deleteMany: {        published: false,      },    },  },  include: {    posts: true,  },});

Update a user by deleting specific posts:

TypeScript
const result = await prisma.user.update({  where: {    id: 6,  },  data: {    posts: {      deleteMany: [{ id: 7 }],    },  },  include: {    posts: true,  },});

You can use a nested updateMany to update all related records for a particular user. The following query unpublishes all posts for a specific user:

TypeScript
const result = await prisma.user.update({  where: {    id: 6,  },  data: {    posts: {      updateMany: {        where: {          published: true,        },        data: {          published: false,        },      },    },  },  include: {    posts: true,  },});
TypeScript
const result = await prisma.user.update({  where: {    id: 6,  },  data: {    posts: {      update: {        where: {          id: 9,        },        data: {          title: "My updated title",        },      },    },  },  include: {    posts: true,  },});

The following query uses a nested upsert to update "bob@prisma.io" if that user exists, or create the user if they do not exist:

TypeScript
const result = await prisma.post.update({  where: {    id: 6,  },  data: {    author: {      upsert: {        create: {          email: "bob@prisma.io",          name: "Bob the New User",        },        update: {          email: "bob@prisma.io",          name: "Bob the existing user",        },      },    },  },  include: {    author: true,  },});
Section titled “Add new related records to an existing record”

You can nest create or createMany inside an update to add new related records to an existing record. The following query adds two posts to a user with an id of 9:

TypeScript
const result = await prisma.user.update({  where: {    id: 9,  },  data: {    posts: {      createMany: {        data: [{ title: "My first post" }, { title: "My second post" }],      },    },  },  include: {    posts: true,  },});

Prisma Client provides the some, every, and none options to filter records by the properties of related records on the "-to-many" side of the relation. For example, filtering users based on properties of their posts.

For example:

Requirement Query option to use
"I want a list of every User that has at least one unpublished Post record" some posts are unpublished
"I want a list of every User that has no unpublished Post records" none of the posts are unpublished
"I want a list of every User that has only unpublished Post records" every post is unpublished

For example, the following query returns User that meet the following criteria:

  • No posts with more than 100 views
  • All posts have less than, or equal to 50 likes
TypeScript
const users = await prisma.user.findMany({  where: {    posts: {      none: {        views: {          gt: 100,        },      },      every: {        likes: {          lte: 50,        },      },    },  },  include: {    posts: true,  },});

Prisma Client provides the is and isNot options to filter records by the properties of related records on the "-to-one" side of the relation. For example, filtering posts based on properties of their author.

For example, the following query returns Post records that meet the following criteria:

  • Author's name is not Bob
  • Author is older than 40
TypeScript
const users = await prisma.post.findMany({  where: {    author: {      isNot: {        name: "Bob",      },      is: {        age: {          gt: 40,        },      },    },  },  include: {    author: true,  },});

For example, the following query uses none to return all users that have zero posts:

TypeScript
const usersWithZeroPosts = await prisma.user.findMany({  where: {    posts: {      none: {},    },  },  include: {    posts: true,  },});

The following query returns all posts that don't have an author relation:

JavaScript
const postsWithNoAuthor = await prisma.post.findMany({  where: {    author: null, // or author: { }  },  include: {    author: true,  },});

The following query returns all users with at least one post:

TypeScript
const usersWithSomePosts = await prisma.user.findMany({  where: {    posts: {      some: {},    },  },  include: {    posts: true,  },});

The fluent API lets you fluently traverse the relations of your models via function calls. Note that the last function call determines the return type of the entire query (the respective type annotations are added in the code snippets below to make that explicit).

This query returns all Post records by a specific User:

TypeScript
const postsByUser: Post[] = await prisma.user
  .findUnique({ where: { email: "alice@prisma.io" } })
  .posts();

This is equivalent to the following findMany query:

TypeScript
const postsByUser = await prisma.post.findMany({
  where: {
    author: {
      email: "alice@prisma.io",
    },
  },
});

The main difference between the queries is that the fluent API call is translated into two separate database queries while the other one only generates a single query (see this GitHub issue)

Note: You can use the fact that .findUnique({ where: { email: 'alice@prisma.io' } }).posts() queries are automatically batched by the Prisma dataloader in Prisma Client to avoid the n+1 problem in GraphQL resolvers.

This request returns all categories by a specific post:

TypeScript
const categoriesOfPost: Category[] = await prisma.post
  .findUnique({ where: { id: 1 } })
  .categories();

Note that you can chain as many queries as you like. In this example, the chaining starts at Profile and goes over User to Post:

TypeScript
const posts: Post[] = await prisma.profile
  .findUnique({ where: { id: 1 } })
  .user()
  .posts();

The only requirement for chaining is that the previous function call must return only a single object (e.g. as returned by a findUnique query or a "to-one relation" like profile.user()).

The following query is not possible because findMany does not return a single object but a list:

TypeScript
// This query is illegal
const posts = await prisma.user.findMany().posts();
Suggest an edit

Propose a replacement for this page. The site team reviews it before applying any changes.

Export
Documentation menu