Skip to main content
Prisma Documentation Docs

Search documentation

Type to search this documentation.

On this pageOverview

CRUD

This page describes how to perform CRUD operations with your generated Prisma Client API. CRUD is an acronym that stands for:

Refer to the Prisma Client API reference documentation for detailed explanations of each method.

All examples are based on the following schema:

Expand for sample schema
databases"
datasource db {

  provider = "postgresql"

}

generator client {

  provider = "prisma-client"

  output   = "./generated"

}

model ExtendedProfile {

  id        Int    @id @default(autoincrement())

  biography String

  user      User   @relation(fields: [userId], references: [id])

  userId    Int    @unique

}

model User {

  id           Int              @id @default(autoincrement())

  name         String?

  email        String           @unique

  profileViews Int              @default(0)

  role         Role             @default(USER)

  coinflips    Boolean[]

  posts        Post[]

  profile      ExtendedProfile?

}

model Post {

  id         Int        @id @default(autoincrement())

  title      String

  published  Boolean    @default(true)

  author     User       @relation(fields: [authorId], references: [id])

  authorId   Int

  comments   Json?

  views      Int        @default(0)

  likes      Int        @default(0)

  categories Category[]

}

model Category {

  id    Int    @id @default(autoincrement())

  name  String @unique

  posts Post[]

}

enum Role {

  USER

  ADMIN

}
MongoDB
datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model ExtendedProfile {
  id        String @id @default(auto()) @map("_id") @db.ObjectId
  biography String
  user      User   @relation(fields: [userId], references: [id])
  userId    String @unique @db.ObjectId
}

model User {
  id           String           @id @default(auto()) @map("_id") @db.ObjectId
  name         String?
  email        String           @unique
  profileViews Int              @default(0)
  role         Role             @default(USER)
  coinflips    Boolean[]
  posts        Post[]
  profile      ExtendedProfile?
}

model Post {
  id         String     @id @default(auto()) @map("_id") @db.ObjectId
  title      String
  published  Boolean    @default(true)
  author     User       @relation(fields: [authorId], references: [id])
  authorId   String     @db.ObjectId
  comments   Json?
  views      Int        @default(0)
  likes      Int        @default(0)
  categories Category[]
}

model Category {
  id    String @id @default(auto()) @map("_id") @db.ObjectId
  name  String @unique
  posts Post[]
}

enum Role {
  USER
  ADMIN
}

For relational databases, use db push command to push the example schema to your own database

title="bun"
bunx prisma db push
pnpm
pnpm prisma db push
yarn
yarn prisma db push
npm
npx prisma db push

For MongoDB, ensure your data is in a uniform shape and matches the model defined in the Prisma schema.

The following query creates (create()) a single user with two fields:

const user = await prisma.user.create({

  data: {

    email: "elsa@prisma.io",

    name: "Elsa Prisma",

  },

});
{

  id: 22,

  name: 'Elsa Prisma',

  email: 'elsa@prisma.io',

  profileViews: 0,

  role: 'USER',

  coinflips: []

}

The user's id is auto-generated, and your schema determines which fields are mandatory.

The following example produces an identical result, but creates a UserCreateInput variable named user outside the context of the create() query. After completing a simple check ("Should posts be included in this create() query?"), the user variable is passed into the query:

import { PrismaClient, Prisma } from "../prisma/generated/client";

const prisma = new PrismaClient();

async function main() {

  let includePosts: boolean = false;

  let user: Prisma.UserCreateInput;

  // Check if posts should be included in the query

  if (includePosts) {

    user = {

      email: "elsa@prisma.io",

      name: "Elsa Prisma",

      posts: {

        create: {

          title: "Include this post!",

        },

      },

    };

  } else {

    user = {

      email: "elsa@prisma.io",

      name: "Elsa Prisma",

    };

  }

  // Pass 'user' object into query

  const createUser = await prisma.user.create({ data: user });

}

main();

For more information about working with generated types, see: Generated types.

Prisma Client supports bulk inserts as a GA feature in 2.20.0 and later.

The following createMany() query creates multiple users and skips any duplicates (email must be unique):

const createMany = await prisma.user.createMany({

  data: [

    { name: "Bob", email: "bob@prisma.io" },

    { name: "Bobo", email: "bob@prisma.io" }, // Duplicate unique key!

    { name: "Yewande", email: "yewande@prisma.io" },

    { name: "Angelique", email: "angelique@prisma.io" },

  ],

  skipDuplicates: true, // Skip 'Bobo'

});
{

  count: 3;

}

createMany() uses a single INSERT INTO statement with multiple values, which is generally more efficient than a separate INSERT per row:

BEGIN

INSERT INTO "public"."User" ("id","name","email","profileViews","role","coinflips","testing","city","country") VALUES (DEFAULT,$1,$2,$3,$4,DEFAULT,DEFAULT,DEFAULT,$5), (DEFAULT,$6,$7,$8,$9,DEFAULT,DEFAULT,DEFAULT,$10), (DEFAULT,$11,$12,$13,$14,DEFAULT,DEFAULT,DEFAULT,$15), (DEFAULT,$16,$17,$18,$19,DEFAULT,DEFAULT,DEFAULT,$20) ON CONFLICT DO NOTHING

COMMIT

SELECT "public"."User"."country", "public"."User"."city", "public"."User"."email", SUM("public"."User"."profileViews"), COUNT(*) FROM "public"."User" WHERE 1=1 GROUP BY "public"."User"."country", "public"."User"."city", "public"."User"."email" HAVING AVG("public"."User"."profileViews") >= $1 ORDER BY "public"."User"."country" ASC OFFSET $2

Note: Multiple create() statements inside a $transaction results in multiple INSERT statements.

The following video demonstrates how to use createMany() and faker.js to seed a database with sample data:

https://www.youtube.com/embed/QxyqR4yh1GI

See Working with relations > Nested writes for information about creating a record and one or more related records at the same time.

You can use createManyAndReturn() in order to create many records and return the resulting objects.

const users = await prisma.user.createManyAndReturn({

  data: [

    { name: "Alice", email: "alice@prisma.io" },

    { name: "Bob", email: "bob@prisma.io" },

  ],

});
[

  {

    id: 22,

    name: "Alice",

    email: "alice@prisma.io",

    profileViews: 0,

    role: "USER",

    coinflips: [],

  },

  {

    id: 23,

    name: "Bob",

    email: "bob@prisma.io",

    profileViews: 0,

    role: "USER",

    coinflips: [],

  },

];

The following queries return a single record (findUnique()) by unique identifier or ID:

// By unique identifier

const user = await prisma.user.findUnique({

  where: {

    email: "elsa@prisma.io",

  },

});

// By ID

const user = await prisma.user.findUnique({

  where: {

    id: 99,

  },

});

If you are using the MongoDB connector and your underlying ID type is ObjectId, you can use the string representation of that ObjectId:

// By ID

const user = await prisma.user.findUnique({

  where: {

    id: "60d5922d00581b8f0062e3a8",

  },

});

The following findMany() query returns all User records:

const users = await prisma.user.findMany();

You can also paginate your results.

The following findFirst() query returns the most recently created user with at least one post that has more than 100 likes:

  1. Order users by descending ID (largest first) - the largest ID is the most recent
  2. Return the first user in descending order with at least one post that has more than 100 likes
const findUser = await prisma.user.findFirst({

  where: {

    posts: {

      some: {

        likes: {

          gt: 100,

        },

      },

    },

  },

  orderBy: {

    id: "desc",

  },

});

Prisma Client supports filtering on record fields and related record fields.

The following query returns all User records with an email that ends in "prisma.io":

const users = await prisma.user.findMany({

  where: {

    email: {

      endsWith: "prisma.io",

    },

  },

});

The following query uses a combination of operators to return users whose name start with E or administrators with at least 1 profile view:

const users = await prisma.user.findMany({

  where: {

    OR: [

      {

        name: {

          startsWith: "E",

        },

      },

      {

        AND: {

          profileViews: {

            gt: 0,

          },

          role: {

            equals: "ADMIN",

          },

        },

      },

    ],

  },

});

The following query returns users with an email that ends with prisma.io and have at least one post (some) that is not published:

const users = await prisma.user.findMany({

  where: {

    email: {

      endsWith: "prisma.io",

    },

    posts: {

      some: {

        published: false,

      },

    },

  },

});

See Working with relations for more examples of filtering on related field values.

The following findUnique() query uses select to return the email and name fields of a specific User record:

const user = await prisma.user.findUnique({

  where: {

    email: "emma@prisma.io",

  },

  select: {

    email: true,

    name: true,

  },

});
{ email: 'emma@prisma.io', name: "Emma" }

For more information about including relations, refer to:

The following query uses a nested select to return:

  • The user's email
  • The likes field of each post
const user = await prisma.user.findUnique({

  where: {

    email: "emma@prisma.io",

  },

  select: {

    email: true,

    posts: {

      select: {

        likes: true,

      },

    },

  },

});
{ email: 'emma@prisma.io', posts: [ { likes: 0 }, { likes: 0 } ] }

For more information about including relations, see Select fields and include relations.

See Select distinct for information about selecting distinct field values.

The following query returns all ADMIN users and includes each user's posts in the result:

const users = await prisma.user.findMany({

  where: {

    role: "ADMIN",

  },

  include: {

    posts: true,

  },

});
{

    "id": 38,

    "name": "Maria",

    "email": "maria@prisma.io",

    "profileViews": 20,

    "role": "ADMIN",

    "coinflips": [

        true,

        false,

        false

    ],

    "posts": []

},

{

    "id": 39,

    "name": "Oni",

    "email": "oni2@prisma.io",

    "profileViews": 20,

    "role": "ADMIN",

    "coinflips": [

        true,

        false,

        false

    ],

    "posts": [

        {

        "id": 25,

        "authorId": 39,

        "title": "My awesome post",

        "published": true,

        "comments": null,

        "views": 0,

        "likes": 0

        }

    ]

}

For more information about including relations, see Select fields and include relations.

See Working with relations to find out how to combine include and where for a filtered list of relations - for example, only include a user's published posts.

The following query uses update() to find and update a single User record by email:

const updateUser = await prisma.user.update({

  where: {

    email: "viola@prisma.io",

  },

  data: {

    name: "Viola the Magnificent",

  },

});
{

   "id": 43,

   "name": "Viola the Magnificent",

   "email": "viola@prisma.io",

   "profileViews": 0,

   "role": "USER",

   "coinflips": [],

}

The following query uses updateMany() to update all User records that contain prisma.io:

const updateUsers = await prisma.user.updateMany({

  where: {

    email: {

      contains: "prisma.io",

    },

  },

  data: {

    role: "ADMIN",

  },

});
{

   "count": 19

}

You can use updateManyAndReturn() in order to update many records and return the resulting objects.

const users = await prisma.user.updateManyAndReturn({

  where: {

    email: {

      contains: "prisma.io",

    },

  },

  data: {

    role: "ADMIN",

  },

});
[

  {

    id: 22,

    name: "Alice",

    email: "alice@prisma.io",

    profileViews: 0,

    role: "ADMIN",

    coinflips: [],

  },

  {

    id: 23,

    name: "Bob",

    email: "bob@prisma.io",

    profileViews: 0,

    role: "ADMIN",

    coinflips: [],

  },

];

The following query uses upsert() to update a User record with a specific email address, or create that User record if it does not exist:

const upsertUser = await prisma.user.upsert({

  where: {

    email: "viola@prisma.io",

  },

  update: {

    name: "Viola the Magnificent",

  },

  create: {

    email: "viola@prisma.io",

    name: "Viola the Magnificent",

  },

});
{

   "id": 43,

   "name": "Viola the Magnificent",

   "email": "viola@prisma.io",

   "profileViews": 0,

   "role": "ADMIN",

   "coinflips": [],

}

Prisma Client does not have a findOrCreate() query. You can use upsert() as a workaround. To make upsert() behave like a findOrCreate() method, provide an empty update parameter to upsert().

Use atomic number operations to update a number field based on its current value - for example, increment or multiply. The following query increments the views and likes fields by 1:

const updatePosts = await prisma.post.updateMany({

  data: {

    views: {

      increment: 1,

    },

    likes: {

      increment: 1,

    },

  },

});

Refer to Working with relations for information about disconnecting (disconnect) and connecting (connect) related records.

The following query uses delete() to delete a single User record:

const deleteUser = await prisma.user.delete({

  where: {

    email: "bert@prisma.io",

  },

});

Attempting to delete a user with one or more posts result in an error, as every Post requires an author - see cascading deletes.

The following query uses deleteMany() to delete all User records where email contains prisma.io:

const deleteUsers = await prisma.user.deleteMany({

  where: {

    email: {

      contains: "prisma.io",

    },

  },

});

Attempting to delete a user with one or more posts result in an error, as every Post requires an author - see cascading deletes.

The following query uses deleteMany() to delete all User records:

const deleteUsers = await prisma.user.deleteMany({});

Be aware that this query will fail if the user has any related records (such as posts). In this case, you need to delete the related records first.

The following query uses delete() to delete a single User record:

const deleteUser = await prisma.user.delete({

  where: {

    email: "bert@prisma.io",

  },

});

However, the example schema includes a required relation between Post and User, which means that you cannot delete a user with posts:

The change you are trying to make would violate the required relation 'PostToUser' between the `Post` and `User` models.

To resolve this error, you can:

  • Make the relation optional:

    model Post {
    
      id       Int   @id @default(autoincrement())
    
      author   User? @relation(fields: [authorId], references: [id]) 
    
      authorId Int?
    
      author   User  @relation(fields: [authorId], references: [id]) 
    
      authorId Int
    
    }
  • Change the author of the posts to another user before deleting the user.

  • Delete a user and all their posts with two separate queries in a transaction (all queries must succeed):

    const deletePosts = prisma.post.deleteMany({
    
      where: {
    
        authorId: 7,
    
      },
    
    });
    
    const deleteUser = prisma.user.delete({
    
      where: {
    
        id: 7,
    
      },
    
    });
    
    const transaction = await prisma.$transaction([deletePosts, deleteUser]);

Sometimes you want to remove all data from all tables but keep the actual tables. This can be particularly useful in a development environment and whilst testing.

The following shows how to delete all records from all tables with Prisma Client and with Prisma Migrate.

When you know the order in which your tables should be deleted, you can use the deleteMany function. This is executed synchronously in a $transaction and can be used with all types of databases.

const deletePosts = prisma.post.deleteMany();

const deleteProfile = prisma.profile.deleteMany();

const deleteUsers = prisma.user.deleteMany();

// The transaction runs synchronously so deleteUsers must run last.

await prisma.$transaction([deleteProfile, deletePosts, deleteUsers]);

✅ Pros:

  • Works well when you know the structure of your schema ahead of time
  • Synchronously deletes each tables data

❌ Cons:

  • When working with relational databases, this function doesn't scale as well as having a more generic solution which looks up and TRUNCATEs your tables regardless of their relational constraints. Note that this scaling issue does not apply when using the MongoDB connector.

Note: The $transaction performs a cascading delete on each models table so they have to be called in order.

If you are comfortable working with raw SQL, you can perform a TRUNCATE query on a table using $executeRawUnsafe.

In the following examples, the first tab shows how to perform a TRUNCATE on a Postgres database by using a $queryRaw look up that maps over the table and TRUNCATES all tables in a single query.

The second tab shows performing the same function but with a MySQL database. In this instance the constraints must be removed before the TRUNCATE can be executed, before being reinstated once finished. The whole process is run as a $transaction

title="PostgreSQL"
const tablenames = await prisma.$queryRaw<

  Array<{ tablename: string }>

>`SELECT tablename FROM pg_tables WHERE schemaname='public'`;

const tables = tablenames

  .map(({ tablename }) => tablename)

  .filter((name) => name !== "_prisma_migrations")

  .map((name) => `"public"."${name}"`)

  .join(", ");

try {

  await prisma.$executeRawUnsafe(`TRUNCATE TABLE ${tables} CASCADE;`);

} catch (error) {

  console.log({ error });

}
MySQL
const transactions: PrismaPromise<any>[] = [];
transactions.push(prisma.$executeRaw`SET FOREIGN_KEY_CHECKS = 0;`);

const tablenames = await prisma.$queryRaw<
  Array<{ TABLE_NAME: string }>
>`SELECT TABLE_NAME from information_schema.TABLES WHERE TABLE_SCHEMA = 'tests';`;

for (const { TABLE_NAME } of tablenames) {
  if (TABLE_NAME !== "_prisma_migrations") {
    try {
      transactions.push(prisma.$executeRawUnsafe(`TRUNCATE ${TABLE_NAME};`));
    } catch (error) {
      console.log({ error });
    }
  }
}

transactions.push(prisma.$executeRaw`SET FOREIGN_KEY_CHECKS = 1;`);

try {
  await prisma.$transaction(transactions);
} catch (error) {
  console.log({ error });
}

✅ Pros:

  • Scalable
  • Very fast

❌ Cons:

  • Can't undo the operation
  • Using reserved SQL key words as tables names can cause issues when trying to run a raw query

If you use Prisma Migrate, you can use migrate reset, this will:

  1. Drop the database
  2. Create a new database
  3. Apply migrations
  4. Seed the database with data
  • A single User
  • Two new, related Post records
  • Connect or create Category per post
const u = await prisma.user.create({

  include: {

    posts: {

      include: {

        categories: true,

      },

    },

  },

  data: {

    email: "emma@prisma.io",

    posts: {

      create: [

        {

          title: "My first post",

          categories: {

            connectOrCreate: [

              {

                create: { name: "Introductions" },

                where: {

                  name: "Introductions",

                },

              },

              {

                create: { name: "Social" },

                where: {

                  name: "Social",

                },

              },

            ],

          },

        },

        {

          title: "How to make cookies",

          categories: {

            connectOrCreate: [

              {

                create: { name: "Social" },

                where: {

                  name: "Social",

                },

              },

              {

                create: { name: "Cooking" },

                where: {

                  name: "Cooking",

                },

              },

            ],

          },

        },

      ],

    },

  },

});
Suggest an edit

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

Export
Documentation menu