Prisma Client API reference
The Prisma Client API reference documentation is based on the following schema:
model User {
id Int @id @default(autoincrement())
name String?
email String @unique
profileViews Int @default(0)
role Role @default(USER)
coinflips Boolean[]
posts Post[]
city String
country String
profile ExtendedProfile?
pets Json
}
model ExtendedProfile {
id Int @id @default(autoincrement())
userId Int? @unique
bio String?
User User? @relation(fields: [userId], references: [id])
}
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)
}
enum Role {
USER
ADMIN
}
All example generated types (such as UserSelect
and UserWhereUniqueInput
) are based on the User
model.
PrismaClient
This section describes the PrismaClient
constructor and its parameters.
Remarks
- Parameters are validated at runtime.
datasources
Programmatically overrides properties of the datasource
block in the schema.prisma
file - for example, as part of an integration test. See also: Data sources
From version 5.2.0 and upwards, you can also use the datasourceUrl
property to programmatically override the database connection string.
Properties
Example property | Example value | Description |
---|---|---|
db | { url: 'file:./dev_qa.db' } | The database connection URL. |
Remarks
- You must re-generate Prisma Client each time you add or rename a data source. Datasource names are included in the generated client.
- If you named your
datasource
block something else in the schema, replacedb
with the name of yourdatasource
block.
Examples
Programmatically override a datasource url
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient({
datasources: {
db: {
url: 'file:./dev_qa.db',
},
},
});
Based on the following datasource
block:
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
datasourceUrl
Programmatically overrides the datasource
block in the schema.prisma
file.
Property
Option | Example value | Description |
---|---|---|
Database connection string | 'file:./dev_qa.db' | The database connection URL. |
Examples
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient({
datasourceUrl: 'postgresql://johndoe:randompassword@localhost:5432/mydb',
});
log
Determines the type and level of logging. See also: Logging
Options
Option | Example |
---|---|
Array of log levels | [ "info", "query" ] |
Array of log definitions | [ { level: "info", emit: "event" }, { level: "warn", emit: "stdout" }] |
Log levels
Name | Example |
---|---|
query | Logs all queries run by Prisma. For relational databases this logs all SQL queries. Example: prisma:query SELECT "public"."User"."id", "public"."User"."email" FROM "public"."User" WHERE ("public"."User"."id") IN (SELECT "t0"."id" FROM "public"."User" AS "t0" INNER JOIN "public"."Post" AS "j0" ON ("j0"."authorId") = ("t0"."id") WHERE ("j0"."views" > $1 AND "t0"."id" IS NOT NULL)) OFFSET $2 For MongoDB this logs queries using the mongosh shell format. Example: prisma:query db.User.deleteMany({ _id: ( $in: [ “6221ce49f756b0721fc00542”, ], }, }) |
info | Example: prisma:info Started http server on http://127.0.0.1:58471 |
warn | Warnings. |
error | Errors. |
Emit formats
Name | Description |
---|---|
stdout | See: stdout |
event | Raises an event that you can subscribe to. |
Event types
The query
event type:
export type QueryEvent = {
timestamp: Date;
query: string; // Query sent to the database
params: string; // Query parameters
duration: number; // Time elapsed (in milliseconds) between client issuing query and database responding - not only time taken to run query
target: string;
};
Note that for MongoDB, the params
and duration
fields will be undefined.
All other log level event types:
export type LogEvent = {
timestamp: Date;
message: string;
target: string;
};
Examples
Log query
and info
to stdout
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient({ log: ['query', 'info'] });
async function main() {
const countUsers = await prisma.user.count({});
}
main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
Log a query
event to console
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient({
log: [{ level: 'query', emit: 'event' }],
});
prisma.$on('query', (e) => {
console.log(e);
});
async function main() {
const countUsers = await prisma.user.count({});
}
main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
Log info
, warn
, and error
events to console
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient({
log: [
{ level: 'warn', emit: 'event' },
{ level: 'info', emit: 'event' },
{ level: 'error', emit: 'event' },
],
});
prisma.$on('warn', (e) => {
console.log(e);
});
prisma.$on('info', (e) => {
console.log(e);
});
prisma.$on('error', (e) => {
console.log(e);
});
async function main() {
const countUsers = await prisma.user.count({});
}
main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
errorFormat
Determines the level and formatting of errors returned by Prisma Client.
Error formats
Name | Description |
---|---|
undefined | If it's not defined, the default is colorless. |
pretty | Enables pretty error formatting. |
colorless (default) | Enables colorless error formatting. |
minimal | Enables minimal error formatting. |
Examples
No error formatting
const prisma = new PrismaClient({
// Defaults to colorless
});
pretty
error formatting
const prisma = new PrismaClient({
errorFormat: 'pretty',
});
colorless
error formatting
const prisma = new PrismaClient({
errorFormat: 'colorless',
});
minimal
error formatting
const prisma = new PrismaClient({
errorFormat: 'minimal',
});
adapter
Defines an instance of a driver adapter. See also Database drivers .
This is available from version 5.4.0 and newer behind the driverAdapters
feature flag.
Example
The example below uses the Neon driver adapter
import { Pool, neonConfig } from '@neondatabase/serverless';
import { PrismaNeon } from '@prisma/adapter-neon';
import { PrismaClient } from '@prisma/client';
import dotenv from 'dotenv';
import ws from 'ws';
dotenv.config();
neonConfig.webSocketConstructor = ws;
const connectionString = `${process.env.DATABASE_URL}`;
const pool = new Pool({ connectionString });
const adapter = new PrismaNeon(pool);
const prisma = new PrismaClient({ adapter });
rejectOnNotFound
Note: rejectOnNotFound
was removed in v5.0.0.
Deprecated: rejectOnNotFound
is deprecated in v4.0.0. From v4.0.0, use the queries findUniqueOrThrow
or findFirstOrThrow
.
Use the rejectOnNotFound
parameter to configure findUnique()
and/or findFirst
to throw an error if the record was not found. By default, both operations return null
if the record is not found.
Remarks
- You can configure
rejectOnNotFound
on a per-request level for bothfindUnique()
andfindFirst
Options
Option | Description |
---|---|
RejectOnNotFound | Enable globally (true / false ) or throw a custom error. |
RejectPerOperation | Enable per operation (true / false ) or throw a custom error per operation, per model. |
Examples
Enable globally for findUnique()
and findFirst
const prisma = new PrismaClient({
rejectOnNotFound: true,
});
Enable globally for a specific operation
const prisma = new PrismaClient({
rejectOnNotFound: {
findUnique: true,
},
});
Throw a custom error per model and operation if record is not found
const prisma = new PrismaClient({
rejectOnNotFound: {
findFirst: {
User: (err) => new Error('User error'),
Post: (err) => new Error('Post error!'),
},
findUnique: {
User: (err) => new Error('User error'),
Post: (err) => new Error('Post error!'),
},
},
});
transactionOptions
Note: transactionOptions
was introduced in v5.10.0.
Allows to set transaction options globally on the constructor level.
Remarks
- The transaction levels can be overridden on a per-transaction level.
Options
Option | Description |
---|---|
maxWait | The maximum amount of time Prisma Client will wait to acquire a transaction from the database. The default value is 2 seconds. |
timeout | The maximum amount of time the interactive transaction can run before being canceled and rolled back. The default value is 5 seconds. |
isolationLevel | Sets the transaction isolation level. By default this is set to the value currently configured in your database. The available can vary depending on the database you use. |
Example
const prisma = new PrismaClient({
transactionOptions: {
isolationLevel: Prisma.TransactionIsolationLevel.Serializable,
maxWait: 5000, // default: 2000
timeout: 10000, // default: 5000
},
});
Model queries
Use model queries to perform CRUD operations on your models. See also: CRUD
findUnique()
findUnique()
query lets you retrieve a single database record:
- By ID
- By a unique attribute
findUnique()
replaced findOne
in version 2.12.0.
Remarks
- Prisma Client's dataloader automatically batches
findUnique()
queries with the sameselect
andwhere
parameters. - If you want the query to throw an error if the record is not found, then consider using
findUniqueOrThrow
instead. - You cannot use filter conditions (e.g.
equals
,contains
,not
) to filter fields of the JSON data type. Using filter conditions will likely result in anull
response for that field.
Options
Name | Example type (User ) | Required | Description |
---|---|---|---|
where | UserWhereUniqueInput | Yes | Wraps all fields of a model so that a record can be selected (learn more). Before version 4.5.0, this type only wraps unique fields of a model. |
select | XOR<UserSelect, null> | No | Specifies which properties to include on the returned object. |
include | XOR<UserInclude, null> | No | Specifies which relations should be eagerly loaded on the returned object. |
omit | XOR<UserOmit, null> | No | Specifies which properties to exclude on the returned object. In Preview since 5.13.0 |
relationLoadStrategy | 'join' or 'query' | No | Default: join . Specifies the load strategy for a relation query. Only available in combination with include (or select on a relation field). In Preview since 5.9.0. |
rejectOnNotFound (deprecated) | RejectOnNotFound | No | If true, throw a NotFoundError: No User found error . You can also configure rejectOnNotFound globally. Note: rejectOnNotFound is deprecated in v4.0.0. From v4.0.0, use findUniqueOrThrow instead. |
Return type
Return type | Example | Description |
---|---|---|
JavaScript object (typed) | User | |
JavaScript object (plain) | { title: "Hello world" } | Use select and include to determine which fields to return. |
null | null | Record not found |
Error | If rejectOnNotFound is true, findUnique() throws an error (NotFoundError by default, customizable globally) instead of returning null . |
Examples
Get the User
record with an id
of 42
const result = await prisma.user.findUnique({
where: {
id: 42,
},
});
Get the User
record with an email
of alice@prisma.io
const result = await prisma.user.findUnique({
where: {
email: 'alice@prisma.io',
},
});
Get the User
record with firstName
of Alice
and lastName
of Smith
(@@unique
)
Expand for example User model with a @@unique block
model User {
firstName String
lastName String
@@unique(fields: [firstName, lastName], name: "fullname")
}
const result = await prisma.user.findUnique({
where: {
fullname: {
// name property of @@unique attribute - default is firstname_lastname
firstName: 'Alice',
lastName: 'Smith',
},
},
});
Get the User
record with firstName
of Alice
and lastName
of Smith
(@@id
)
Expand for example User model with an @@id block
model User {
firstName String
lastName String
@@id([firstName, lastName])
}
const result = await prisma.user.findUnique({
where: {
firstName_lastName: {
firstName: 'Alice',
lastName: 'Smith',
},
},
});
findUniqueOrThrow()
We introduced findUniqueOrThrow
in v4.0.0. It replaces the rejectOnNotFound
option. rejectOnNotFound
is deprecated in v4.0.0.
findUniqueOrThrow
retrieves a single data record in the same way as findUnique()
. However, if the query does not find a record, it returns NotFoundError: No User found error
.
findUniqueOrThrow
differs from findUnique()
as follows:
-
Its return type is non-nullable. For example,
post.findUnique()
can returnpost
ornull
, butpost.findUniqueOrThrow()
always returnspost
. -
It is not compatible with sequential operations in the
$transaction
API. If the query returnsNotFoundError
, then the API will not roll back any operations in the array of calls. As a workaround, you can use interactive transactions with the$transaction
API, as follows:$transaction(async (prisma) => {
await prisma.model.create({ data: { ... });
await prisma.model.findUniqueOrThrow();
})
findFirst()
findFirst
returns the first record in a list that matches your criteria.
Remarks
- If you want the query to throw an error if the record is not found, then consider using
findFirstOrThrow
instead.
Options
| Name | Example type (User
) | Required | Description |
| ------------------------------- | ------------------------------------------------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- |
| select
| XOR<UserSelect, null>
| No | Specifies which properties to include on the returned object. |
| include
| XOR<UserInclude, null>
| No | Specifies which relations should be eagerly loaded on the returned object. |
| omit
| XOR<UserOmit, null>
| No | Specifies which properties to exclude on the returned object. In Preview since 5.13.0. |
| relationLoadStrategy
| 'join'
or 'query'
| No | Default: join
. Specifies the load strategy for a relation query. Only available in combination with include
(or select
on a relation field). In Preview since 5.9.0. |
| where
| UserWhereInput
| No | Wraps all model fields in a type so that the list can be filtered by any property. |
| orderBy
| XOR<Enumerable<User
OrderByInput>,UserOrderByInput>
| No | Lets you order the returned list by any property. |
| cursor
| UserWhereUniqueInput
| No | Specifies the position for the list (the value typically specifies an id
or another unique value). |
| take
| number
| No | Specifies how many objects should be returned in the list. When used with findFirst
, take
is implicitly 1
or -1
. findFirst
is only affected by whether the value is positive or negative - any negative value reverses the list. |
| skip
| number
| No | Specifies how many of the returned objects in the list should be skipped. |
| distinct
| Enumerable<UserDistinct
FieldEnum>
| No | Lets you filter out duplicate rows by a specific field - for example, return only distinct Post
titles. |
| rejectOnNotFound
(deprecated) | RejectOnNotFound
| No | If true, throw a NotFoundError: No User found error
. You can also configure rejectOnNotFound
globally.
Note: rejectOnNotFound
is deprecated in v4.0.0. From v4.0.0, use findFirstOrThrow
instead. | |
Return type
Return type | Example | Description |
---|---|---|
JavaScript object (typed) | User | Specifies which properties to include on the returned object. |
JavaScript object (plain) | { title: "Hello world" } | Use select and include to determine which fields to return. |
null | null | Record not found |
Error | If rejectOnNotFound is true, findUnique() throws an error (NotFoundError by default, customizable globally) instead of returning null . |
Remarks
findFirst
callsfindMany
behind the scenes and accepts the same query options.- Passing in a negative
take
value when you use afindFirst
query reverses the order of the list.
Examples
See Filter conditions and operators for examples of how to filter results.
Get the first User
record where the name
is Alice
const user = await prisma.user.findFirst({
where: { name: 'Alice' },
});
Get the first Post
record where the title
starts with A test
, reverse the list with take
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient({});
async function main() {
const a = await prisma.post.create({
data: {
title: 'A test 1',
},
});
const b = await prisma.post.create({
data: {
title: 'A test 2',
},
});
const c = await prisma.post.findFirst({
where: {
title: {
startsWith: 'A test',
},
},
orderBy: {
title: 'asc',
},
take: -1, // Reverse the list
});
}
main();
findFirstOrThrow()
We introduced findFirstOrThrow
in v4.0.0. It replaces the rejectOnNotFound
option. rejectOnNotFound
is deprecated in v4.0.0.
findFirstOrThrow
retrieves the first record in a list in the same way as findFirst
. However, if the query does not find a record, it returns NotFoundError: No User found error
.
findFirstOrThrow
differs from findFirst
as follows:
-
Its return type is non-nullable. For example,
post.findFirst()
can returnpost
ornull
, butpost.findFirstOrThrow
always returnspost
. -
It is not compatible with sequential operations in the
$transaction
API. If the query returnsNotFoundError
, then the API will not roll back any operations in the array of calls. As a workaround, you can use interactive transactions with the$transaction
API, as follows:prisma.$transaction(async (tx) => {
await tx.model.create({ data: { ... });
await tx.model.findFirstOrThrow();
})
findMany()
findMany
returns a list of records.
Options
Name | Type | Required | Description |
---|---|---|---|
select | XOR<PostSelect, null> | No | Specifies which properties to include on the returned object. |
include | XOR<PostInclude, null> | No | Specifies which relations should be eagerly loaded on the returned object. |
omit | XOR<PostOmit, null> | No | Specifies which properties to exclude on the returned object. In Preview since 5.13.0 |
relationLoadStrategy | 'join' or 'query' | No | Default: join . Specifies the load strategy for a relation query. Only available in combination with include (or select on a relation field). In Preview since 5.9.0. |
where | UserWhereInput | No | Wraps all model fields in a type so that the list can be filtered by any property. |
orderBy | XOR<Enumerable<PostOrder ByInput>, PostOrderByInput> | No | Lets you order the returned list by any property. |
cursor | UserWhereUniqueInput | No | Specifies the position for the list (the value typically specifies an id or another unique value). |
take | number | No | Specifies how many objects should be returned in the list (as seen from the beginning (positive value) or end (negative value) either of the list or from the cursor position if mentioned) |
skip | number | No | Specifies how many of the returned objects in the list should be skipped. |
distinct | Enumerable<UserDistinctFieldEnum> | No | Lets you filter out duplicate rows by a specific field - for example, return only distinct Post titles. |
Return type
Return type | Example | Description |
---|---|---|
JavaScript array object (typed) | User[] | |
JavaScript array object (plain) | [{ title: "Hello world" }] | Use select and include to determine which fields to return. |
Empty array | [] | No matching records found. |
Examples
See Filter conditions and operators for examples of how to filter results.
Get all User
records where the name
is Alice
const user = await prisma.user.findMany({
where: { name: 'Alice' },
});
create()
create
creates a new database record.
Options
Name | Type | Required | Description |
---|---|---|---|
data | XOR<UserCreateInput, UserUncheckedCreateInput> | Yes | Wraps all the model fields in a type so that they can be provided when creating new records. It also includes relation fields which lets you perform (transactional) nested inserts. Fields that are marked as optional or have default values in the datamodel are optional. |
select | XOR<UserSelect, null> | No | Specifies which properties to include on the returned object. |
include | XOR<UserInclude, null> | No | Specifies which relations should be eagerly loaded on the returned object. |
omit | XOR<UserOmit, null> | No | Specifies which properties to exclude on the returned object. In Preview since 5.13.0 |
relationLoadStrategy | 'join' or 'query' | No | Default: join . Specifies the load strategy for a relation query. Only available in combination with include (or select on a relation field). In Preview since 5.9.0. |
Return type
Return type | Example | Description |
---|---|---|
JavaScript object (typed) | User | |
JavaScript object (plain) | { name: "Alice Wonderland" } | Use select and include to determine which fields to return. |
Remarks
- You can also perform a nested
create
- for example, add aUser
and twoPost
records at the same time.
Examples
Create a single new record with the only required field email
const user = await prisma.user.create({
data: { email: 'alice@prisma.io' },
});
Create multiple new records
In most cases, you can carry out batch inserts with the createMany()
or createManyAndReturn()
queries. However, there are scenarios where create()
is the best option to insert multiple records.
The following example results in two INSERT
statements:
import { Prisma, PrismaClient } from '@prisma/client';
const prisma = new PrismaClient({ log: ['query'] });
async function main() {
let users: Prisma.UserCreateInput[] = [
{
email: 'ariana@prisma.io',
name: 'Ari',
profileViews: 20,
coinflips: [true, false, false],
role: 'ADMIN',
},
{
email: 'elsa@prisma.io',
name: 'Elsa',
profileViews: 20,
coinflips: [true, false, false],
role: 'ADMIN',
},
];
await Promise.all(
users.map(async (user) => {
await prisma.user.create({
data: user,
});
})
);
}
main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
prisma:query BEGIN
prisma:query INSERT INTO "public"."User" ("name","email","profileViews","role","coinflips") VALUES ($1,$2,$3,$4,$5) RETURNING "public"."User"."id"
prisma:query SELECT "public"."User"."id", "public"."User"."name", "public"."User"."email", "public"."User"."profileViews", "public"."User"."role", "public"."User"."coinflips" FROM "public"."User" WHERE "public"."User"."id" = $1 LIMIT $2 OFFSET $3
prisma:query INSERT INTO "public"."User" ("name","email","profileViews","role","coinflips") VALUES ($1,$2,$3,$4,$5) RETURNING "public"."User"."id"
prisma:query COMMIT
prisma:query SELECT "public"."User"."id", "public"."User"."name", "public"."User"."email", "public"."User"."profileViews", "public"."User"."role", "public"."User"."coinflips" FROM "public"."User" WHERE "public"."User"."id" = $1 LIMIT $2 OFFSET $3
prisma:query COMMIT
update()
update
updates an existing database record.
Options
Name | Type | Required | Description |
---|---|---|---|
data | XOR<UserUpdateInput UserUncheckedUpdateInput> | Yes | Wraps all the fields of the model so that they can be provided when updating an existing record. Fields that are marked as optional or have default values in the datamodel are optional. |
where | UserWhereUniqueInput | Yes | Wraps all fields of a model so that a record can be selected (learn more). Before version 4.5.0, this type only wraps unique fields of a model. |
select | XOR<UserSelect, null> | No | Specifies which properties to include on the returned object. |
include | XOR<UserInclude, null> | No | Specifies which relations should be eagerly loaded on the returned object. |
omit | XOR<UserOmit, null> | No | Specifies which properties to exclude on the returned object. In Preview since 5.13.0. |
relationLoadStrategy | 'join' or 'query' | No | Default: join . Specifies the load strategy for a relation query. Only available in combination with include (or select on a relation field). In Preview since 5.9.0. |
Return type
Return type | Example | Description |
---|---|---|
JavaScript object (typed) | User | |
JavaScript object (plain) | { name: "Alice Wonderland" } | Use select and include to determine which fields to return. |
RecordNotFound exception | Exception is thrown if record does not exist. |
Remarks
- To perform arithmetic operations on update (add, subtract, multiply, divide), use atomic updates to prevent race conditions.
- You can also perform a nested
update
- for example, update a user and that user's posts at the same time.
Examples
Update the email
of the User
record with id
of 1
to alice@prisma.io
const user = await prisma.user.update({
where: { id: 1 },
data: { email: 'alice@prisma.io' },
});
upsert()
This section covers the usage of the upsert()
operation. To learn about using nested upsert queries within update()
, reference the linked documentation.
upsert
does the following:
- If an existing database record satisfies the
where
condition, it updates that record - If no database record satisfies the
where
condition, it creates a new database record
Options
Name | Type | Required | Description |
---|---|---|---|
create | XOR<UserCreateInput, UserUncheckedCreateInput> | Yes | Wraps all the fields of the model so that they can be provided when creating new records. It also includes relation fields which lets you perform (transactional) nested inserts. Fields that are marked as optional or have default values in the datamodel are optional. |
update | XOR<UserUpdateInput, UserUncheckedUpdateInput> | Yes | Wraps all the fields of the model so that they can be provided when updating an existing record. Fields that are marked as optional or have default values in the datamodel are optional. |
where | UserWhereUniqueInput | Yes | Wraps all fields of a model so that a record can be selected (learn more). Before version 4.5.0, this type only wraps unique fields of a model. |
select | XOR<UserSelect, null> | No | Specifies which properties to include on the returned object. |
include | XOR<UserInclude, null> | No | Specifies which relations should be eagerly loaded on the returned object. |
omit | XOR<UserOmit, null> | No | Specifies which properties to exclude on the returned object. In Preview since 5.13.0 |
relationLoadStrategy | 'join' or 'query' | No | Default: join . Specifies the load strategy for a relation query. Only available in combination with include (or select on a relation field). In Preview since 5.9.0. |
Return type
Return type | Example | Description |
---|---|---|
JavaScript object (typed) | User | |
JavaScript object (plain) | { name: "Alice Wonderland" } | Use select and include to determine which fields to return. |
Remarks
- To perform arithmetic operations on update (add, subtract, multiply, divide), use atomic updates to prevent race conditions.
- If two or more upsert operations happen at the same time and the record doesn't already exist, then a race condition might happen. As a result, one or more of the upsert operations might throw a unique key constraint error. Your application code can catch this error and retry the operation. Learn more.
- From version 4.6.0, Prisma ORM hands over upsert queries to the database where possible. Learn more.
Examples
Update (if exists) or create a new User
record with an email
of alice@prisma.io
const user = await prisma.user.upsert({
where: { id: 1 },
update: { email: 'alice@prisma.io' },
create: { email: 'alice@prisma.io' },
});
Unique key constraint errors on upserts
Problem
If multiple upsert operations happen at the same time and the record doesn't already exist, then one or more of the operations might return a unique key constraint error.
Cause
When Prisma Client does an upsert, it first checks whether that record already exists in the database. To make this check, Prisma Client performs a read operation with the where
clause from the upsert operation. This has two possible outcomes, as follows:
- If the record does not exist, then Prisma Client creates that record.
- If the record exists, then Prisma Client updates it.
When your application tries to perform two or more concurrent upsert operations, then a race condition might happen where two or more operations do not find the record and therefore try to create that record. In this situation, one of the operations successfully creates the new record but the other operations fail and return a unique key constraint error.
Solution
Handle the P2002 error in your application code. When it occurs, retry the upsert operation to update the row.
Database upserts
Where possible, Prisma Client hands over an upsert
query to the database. This is called a database upsert.
Database upserts have the following advantages:
- They are faster than upserts handled by Prisma Client
- Unique key constraint errors cannot happen
Prisma Client uses a database upsert automatically when specific criteria are met. When these criteria are not met, Prisma Client handles the upsert
.
To use a database upsert, Prisma Client sends the SQL construction INSERT ... ON CONFLICT SET .. WHERE
to the database.
Database upsert prerequisites
Prisma Client can use database upserts if your stack meets the following criteria:
- You use Prisma ORM version 4.6.0 or later
- Your application uses a CockroachDB, PostgreSQL, or SQLite data source
Database upsert query criteria
Prisma Client uses a database upsert for an upsert
query when the query meets the following criteria:
- There are no nested queries in the
upsert
'screate
andupdate
options - The query does not include a selection that uses a nested read
- The query modifies only one model
- There is only one unique field in the
upsert
'swhere
option - The unique field in the
where
option and the unique field in thecreate
option have the same value
If your query does not meet these criteria, then Prisma Client handles the upsert itself.
Database upsert examples
The following examples use this schema:
model User {
id Int @id
profileViews Int
userName String @unique
email String
@@unique([id, profileViews])
}
The following upsert
query meets all of the criteria, so Prisma Client uses a database upsert.
prisma.user.upsert({
where: {
userName: 'Alice',
},
create: {
id: 1,
profileViews: 1,
userName: 'Alice',
email: 'alice@prisma.io',
},
update: {
email: 'updated@example.com',
},
});
In this situation, Prisma uses the following SQL query:
INSERT INTO "public"."User" ("id","profileViews","userName","email") VALUES ($1,$2,$3,$4)
ON CONFLICT ("userName") DO UPDATE
SET "email" = $5 WHERE ("public"."User"."userName" = $6 AND 1=1) RETURNING "public"."User"."id", "public"."User"."profileViews", "public"."User"."userName", "public"."User"."email"
The following query has multiple unique values in the where
clause, so Prisma Client does not use a database upsert:
prisma.User.upsert({
where: {
userName: 'Alice',
profileViews: 1,
id: 1,
},
create: {
id: 1,
profileViews: 1,
userName: 'Alice',
email: 'alice@prisma.io',
},
update: {
email: 'updated@example.com',
},
});
In the following query, the values for userName
in the where
and create
options are different, so Prisma Client does not use a database upsert.
prisma.User.upsert({
where: {
userName: 'Alice',
},
create: {
id: 1,
profileViews: 1,
userName: 'AliceS',
email: 'alice@prisma.io',
},
update: {
email: 'updated@example.com',
},
});
In the following query, the selection on the title
field in posts
is a nested read, so Prisma Client does not use a database upsert.
prisma.user.upsert({
select: {
email: true,
id: true,
posts: {
select: {
title: true,
},
},
},
where: {
userName: 'Alice',
},
create: {
id: 1,
profileViews: 1,
userName: 'Alice',
email: 'alice@prisma.io',
},
update: {
email: 'updated@example.com',
},
});
delete()
delete
deletes an existing database record. You can delete a record:
- By ID
- By a unique attribute
To delete records that match a certain criteria, use deleteMany
with a filter.
Options
Name | Type | Required | Description |
---|---|---|---|
where | UserWhereUniqueInput | Yes | Wraps all fields of a model so that a record can be selected (learn more). Before version 4.5.0, this type only wraps unique fields of a model. |
select | XOR<UserSelect, null> | No | Specifies which properties to include on the returned object. |
include | XOR<UserInclude, null> | No | Specifies which relations should be eagerly loaded on the returned object. |
omit | XOR<UserOmit, null> | No | Specifies which properties to exclude on the returned object. In Preview since 5.13.0 |
relationLoadStrategy | 'join' or 'query' | No | Default: join . Specifies the load strategy for a relation query. Only available in combination with include (or select on a relation field). In Preview since 5.9.0. |
Return type
Return type | Example | Description |
---|---|---|
JavaScript object (typed) | User | The User record that was deleted. |
JavaScript object (plain) | { name: "Alice Wonderland" } | Data from the User record that was deleted. Use select and include to determine which fields to return. |
RecordNotFound exception | Throws an exception if record does not exist. |
Remarks
- To delete multiple records based on some criteria (for example, all
User
records with aprisma.io
email address, usedeleteMany
)