Upgrade to Prisma ORM 6
Prisma ORM v6 introduces a number of breaking changes when you upgrade from an earlier Prisma ORM version. This guide explains how this upgrade might affect your application and gives instructions on how to handle any changes.
Upgrade the prisma
and @prisma/client
packages to v6
To upgrade to Prisma ORM v6 from an earlier version, you need to update both the prisma
and @prisma/client
packages:
- npm
- yarn
- pnpm
- bun
npm install @prisma/client@6
npm install -D prisma@6
yarn up prisma@6 @prisma/client@6
pnpm upgrade prisma@6 @prisma/client@6
bun add @prisma/client@6
bun add prisma@6 --dev
Before you upgrade, check each breaking change below to see how the upgrade might affect your application.
Breaking changes
This section gives an overview of breaking changes in Prisma ORM v6.
Minimum supported Node.js versions
The new minimum supported Node.js versions for Prisma ORM v6 are:
- for Node.js 18 the minimum supported version is 18.18.0
- for Node.js 20 the minimum supported version is 20.9.0
- for Node.js 22 the minimum supported version is 22.11.0
There is no official support for Node.js 16, 17, 19 and 21.
Minimum supported TypeScript version
The new minimum supported TypeScript version for Prisma ORM v6 is: 5.1.0.
Schema change for implicit m-n relations on PostgreSQL
If you're using PostgreSQL and are defining implicit many-to-many relations in your Prisma schema, Prisma ORM maintains the relation table for you under the hood. This relation table has A
and B
columns to represent the tables of the models that are part of this relation.
Previous versions of Prisma ORM used to create a unique index on these two columns. In Prisma v6, this unique index is changing to a primary key in order to simplify for the default replica identity behaviour.
Expand for an example
As an example, consider the following Prisma schema with an implicit m-n relation between Post
and Tag
models:
model Post {
id Int @id @default(autoincrement())
title String
categories Tag[]
}
model Tag {
id Int @id @default(autoincrement())
name String
posts Post[]
}
In this case, Prisma ORM maintains the following relation table for you under the hood:
-- CreateTable
CREATE TABLE "_PostToTag" (
"A" INTEGER NOT NULL,
"B" INTEGER NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "_PostToTag_AB_unique" ON "_PostToTag"("A", "B");
-- CreateIndex
CREATE INDEX "_PostToTag_B_index" ON "_PostToTag"("B");
-- AddForeignKey
ALTER TABLE "_PostToTag" ADD CONSTRAINT "_PostToTag_A_fkey" FOREIGN KEY ("A") REFERENCES "Post"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "_PostToTag" ADD CONSTRAINT "_PostToTag_B_fkey" FOREIGN KEY ("B") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE;
In Prisma v6, the UNIQUE INDEX
is changing into a PRIMARY KEY
:
-- CreateTable
CREATE TABLE "_PostToTag" (
"A" INTEGER NOT NULL,
"B" INTEGER NOT NULL,
CONSTRAINT "_PostToTag_AB_pkey" PRIMARY KEY ("A","B")
);
-- CreateIndex
CREATE INDEX "_PostToTag_B_index" ON "_PostToTag"("B");
-- AddForeignKey
ALTER TABLE "_PostToTag" ADD CONSTRAINT "_PostToTag_A_fkey" FOREIGN KEY ("A") REFERENCES "Post"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "_PostToTag" ADD CONSTRAINT "_PostToTag_B_fkey" FOREIGN KEY ("B") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE;
If you're defining implicit m-n relations in your Prisma schema, the next migration you'll create will contain ALTER TABLE
statements for all the relation tables that belong to these relations. These will look similar to this:
-- AlterTable
ALTER TABLE "_PostToTag" ADD CONSTRAINT "_PostToTag_AB_pkey" PRIMARY KEY ("A", "B");
-- DropIndex
DROP INDEX "_PostToTag_AB_unique";
In order to isolate these schema changes (and not having them bundled with your next migration), we recommend that you create a new migration right after having upgraded to Prisma v6:
npx prisma migrate dev --name upgrade-to-v6
That way, you have a single, dedicated migration that takes care of this schema change and otherwise keeps your migration history clean.
Full-text search on PostgreSQL
The fullTextSearch
Preview feature is promoted to General Availability only for MySQL. This means that if you're using PostgreSQL and currently make use of this Preview feature, you now need to use the new fullTextSearchPostgres
Preview feature:
Before
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
previewFeatures = ["fullTextSearch"]
}
After
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
previewFeatures = ["fullTextSearchPostgres"]
}
Usage of Buffer
In an effort to improve compatibility between Prisma and new modern JavaScript runtimes, we're gradually moving away from Node.js-specific APIs in favor of standard JavaScript.
Prisma v6 replaces the usage of Buffer
with Uint8Array
to represent fields of type Bytes
. Make sure to replace all your occurences of the Buffer
type with the new Uint8Array
.
Expand to view how to convert between Buffer
and Uint8Array
Conversion from Buffer
to Uint8Array
You can directly use the Buffer
instance as a Uint8Array
:
const buffer: Buffer = Buffer.from([1, 2, 3, 4]);
const uint8Array: Uint8Array = buffer; // No conversion needed
Conversion from Uint8Array
to Buffer
You can create a Buffer
from a Uint8Array
using Buffer.from
:
const uint8Array: Uint8Array = new Uint8Array([1, 2, 3, 4]);
const buffer: Buffer = Buffer.from(uint8Array.buffer);
Before
- Code
- Prisma schema
import { PrismaClient } from '@prisma/client'
async function main() {
const prisma = new PrismaClient()
await prisma.user.deleteMany()
const bytesCreated = await prisma.user.create({
data: {
bytes: Buffer.from([1, 2, 3, 4]),
},
})
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
// `bytesCreated` used to have type: {
// bytes: Buffer
// id: number
// }
for (const bytesFound of await prisma.user.findMany()) {
bytesFound.bytes // Buffer [ 1, 2, 3, 4 ]
}
}
main()
model User {
id Int @id @default(autoincrement())
bytes Bytes
}
After
- Code
- Prisma schema
import { PrismaClient } from '@prisma/client'
async function main() {
const prisma = new PrismaClient()
await prisma.user.deleteMany()
const bytesCreated = await prisma.user.create({
data: {
bytes: Uint8Array.from([1, 2, 3, 4]),
},
})
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
// `bytesCreated` now has type: {
// bytes: Uint8Array
// id: number
// }
for (const bytesFound of await prisma.user.findMany()) {
bytesFound.bytes // Uint8Array [ 1, 2, 3, 4 ]
}
}
main()
model User {
id Int @id @default(autoincrement())
bytes Bytes
}
Removed NotFoundError
In Prisma v6, we removed the NotFoundError
in favor of PrismaClientKnownRequestError
with error code P2025
in findUniqueOrThrow()
and findFirstOrThrow()
. If you've relied on catching NotFoundError
instances in your code, you need to adjust the code accordingly.
Before
import { PrismaClient, NotFoundError } from '@prisma/client';
// inside an `async` function
try {
const user = await prisma.user.findUniqueOrThrow({
where: { id: 42 },
});
console.log(user);
} catch (error) {
if (error instanceof NotFoundError) {
console.error("User not found!");
}
else {
console.error("Unexpected error:", error);
}
}
After
import { PrismaClient, Prisma } from '@prisma/client';
// inside an `async` function
try {
const user = await prisma.user.findUniqueOrThrow({
where: { id: 42 },
});
console.log(user);
} catch (error) {
if (
error instanceof Prisma.PrismaClientKnownRequestError &&
error.code === 'P2025' // Specific code for "record not found"
) {
console.error("User not found!");
}
else {
console.error("Unexpected error:", error);
}
}
New keywords that can't be used as model names: async
, await
, using
With this release, you can't use async
, await
and using
as model names any more.
Preview features promoted to General Availability
In this release, we are promoting a number of Preview features to General Availability.
fullTextIndex
If you use the full-text index feature in your app, you can now remove fullTextIndex
from the previewFeatures
in your Prisma schema:
generator client {
provider = "prisma-client-js"
previewFeatures = ["fullTextIndex"]
}
fullTextSearch
If you use the full-text search feature with MySQL in your app, you can now remove fullTextSearch
from the previewFeatures
in your Prisma schema:
generator client {
provider = "prisma-client-js"
previewFeatures = ["fullTextSearch"]
}
If you are using it with PostgreSQL, you need to update the name of the feature flag to fullTextSearchPostgres
:
generator client {
provider = "prisma-client-js"
previewFeatures = ["fullTextSearchPostgres"]
}