Updated January 15, 2026 to reflect Prisma 7.x stable releases and common issues encountered in production upgrades.
If you want to skip ahead, there’s a minimal reproduction repo here, you can reference.
Prisma 7 shipped with a significant architectural change: the query engine was rewritten from Rust to TypeScript. This sounds like a minor internal detail, but it affects how we configure, deploy, and troubleshoot Prisma in NestJS applications.
In this article I’ll quickly go over the steps I took to update Prisma to the new rust free implementation, that is now “GA” as of Prisma version 7.0.0., as indicated by the recent blog on the topic:
https://www.prisma.io/blog/rust-free-prisma-orm-is-ready-for-production.
Prisma also released their own upgrade guide with version 7.0.0:
https://prisma.io/changelog#log2025-11-19
Why the Rust-Free Client Matters
The “old” Prisma architecture used a Rust-based query engine that communicates with your TypeScript code through a serialization layer. This works, but the JavaScript-to-Rust communication was the bottleneck, not the Rust code itself.
By rebuilding the query engine in TypeScript, Prisma eliminated that serialization overhead. The results:
- 90% smaller bundle size: From ~14MB down to ~1.6MB
- Up to 3.4x faster queries: No more cross-language serialization
- Simpler deployment: No native binaries to manage for different platforms
It seems counter intuitive, seeing how you would think that Rust should be faster than TypeScript.
The trade-off is that Prisma no longer bundles database drivers. We now need to install and configure driver adapters explicitly.
I would say for most codebases this is a completely acceptable (and preferable!) tradeoff.
Before You Start: Requirements
Before attempting the upgrade, verify your environment meets these requirements:
Node.js: Version 20.19.0 or higher. Node 22.x is recommended. Check with node --version
TypeScript: Version 5.4.0 or higher. Version 5.9.x is recommended. Check with npx tsc --version (or equivalent)
ESM Configuration: Prisma 7 ships as an ESM module. Your tsconfig.json needs ESM-compatible settings.
Database Support: PostgreSQL, MySQL, SQLite, SQL Server, and CockroachDB are supported. MongoDB is not yet supported in v7.
If you’re using MongoDB, stay on Prisma 6 for now.
If any of these requirements aren’t met, the upgrade will fail in confusing ways. Better to check upfront.
Step 1: Update dependencies
Pro tip: Start on a separate branch. This upgrade touches configuration files that are easy to roll back if something goes wrong.
First things first, first we need to update to the most recent version of Prisma. As of this writing its 7.2.0, which includes a few patch fixes.
Remove old packages and install new ones:
yarn remove prisma @prisma/client @prisma/adapter-pg && yarn add -D prisma && yarn add @prisma/client @prisma/adapter-pg
This nifty one liner does it all.
The `@prisma/adapter-pg` package is the PostgreSQL driver adapter. If you’re using a different database, install the appropriate adapter:
– PostgreSQL: @prisma/adapter-pg
– MySQL: @prisma/adapter-mariadb
– SQLite: @prisma/adapter-better-sqlite3
– SQL Server: @prisma/adapter-mssql
You can see a full list here.
This is what I meant with an acceptable tradeoff, this adapter now handles the actual database connection. Prisma no longer bundles these drivers internally. So we have to be explicit about the one we need.
Step 2: Configure prisma.config.ts
Secondly we need to create a prisma.config.ts in the root of the project. Previously, a configuration was allowed via package.json, but that option is now being deprecated as of version 7.0.0. While not strictly required yet, Setting this up now avoids future migration headaches.
Additionally, using this configuration file allows us to split our schema into multiple files, which can help organize things a bit.
Here’s the simple prisma.config.ts I am using:
import * as path from 'node:path';
import dotenv from 'dotenv';
import { env, PrismaConfig } from 'prisma/config';
dotenv.config();
export default {
datasource: {
url: env('DATABASE_URL'),
},
/**
* The path to the Prisma schema file.
*/
schema: path.join('prisma', 'schema'),
migrations: {
path: path.join('prisma', 'migrations'),
seed: 'ts-node -r tsconfig-paths/register src/config/database/seed.ts',
},
} satisfies PrismaConfig;
The important change here is the datasource.url property. Previously, you specified the database URL in schema.prisma. Now it belongs in prisma.config.ts.
Move the url configuration to prisma.config.ts
Note the new datasource block, in the file above which now contains the URL.
This bit is important. If you used to do to have it in your schema.prisma configuration, something like this:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL") // ❌ This has to go
extensions = []
}
This will no longer work.
You have to remove the ‘url’ from here (don’t worry, Prisma will warn you about this). Be sure to include it in prisma.config.ts as suggested above.
Step 3: Update schema.prisma
The important configuration happens in our schema.prisma file, where we now have to let Prisma know, we want to use the rust free client.
This means changing the provider property and adding the new output and engineType properties, as so:
generator client {
provider = "prisma-client"
output = "../../src/config/database/generated"
engineType = "client"
previewFeatures = ["postgresqlExtensions"]
}
provider: Changed from prisma-client-js to prisma-client. This tells Prisma to generate the new TypeScript-based client.
output: Specifies where to generate the client.
engineType: Set to "client" to use the rust-free engine. This is now the default in Prisma 7, but being explicit helps with clarity.
It is extremely important, that you never generate the client into node_modules. This breaks in unexpected ways and makes debugging painful.
Make sure to not provide an url property under the datasource block. Prisma will complain about this.
For NestJS it seems that it is very important that the output is specified within the src folder, otherwise NestJS cant find it for compilation, and it won’t read the files.
Step 4: Refactor PrismaService
In order for the new rust free PrismaClient to work, we need to import it into our application.
The PrismaService needs to create and pass a driver adapter to the PrismaClient constructor.
Luckily, I was already using Prisma through a service, that I can import across the application, so I simply chose to update the Service:
import { Injectable, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PrismaPg } from '@prisma/adapter-pg';
import { PrismaClient } from './generated/prisma/client';
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
constructor(private configService: ConfigService) {
const adapter = new PrismaPg({
connectionString: configService.get<string>('DATABASE_URL')
});
super({ adapter });
}
async onModuleInit() {
await this.$connect();
}
}
Notice that PrismaClient is now imported directly from the generated folder, not from @prisma/client. This is intentional. The generated client contains your specific schema types.
Additionally, before we call super I am creating an adapter with the @prisma/adapter-pg library.
The `PrismaPg` adapter handles connection pooling. The defaults changed in Prisma 7, so if you experience timeout issues after upgrading, you may need to configure pool settings explicitly:
const adapter = new PrismaPg({
connectionString: configService.get<string>('DATABASE_URL'),
pool: {
max: 10,
connectionTimeoutMillis: 30000,
},
});
That’s almost it!
Step 5: Update Imports Across the Codebase
The final thing we have to do, is ensure we are never using @prisma/client anywhere in the codebase.
So, every single import from needs to change. The legacy package no longer contains the generated types.
Search your codebase for:
import { PrismaClient } from '@prisma/client';
import { User, Post } from '@prisma/client';
import type { Prisma } from '@prisma/client';
Replace with imports from your generated folder:
import { PrismaClient } from './generated/prisma/client';
import { User, Post } from './generated/prisma/client';
import type { Prisma } from './generated/prisma/client';
For projects using the PrismaService pattern, like mine, most of your code should already be importing through the service rather than directly from @prisma/client.
But check for edge cases like seed scripts, utility functions, or test files. Better safe than sorry.
I went through the application, and had to update a few imports, and a single instance of new PrismaClient (from my Stripe Module), but I could simply and easily remove those and replace them with importing the PrismaService.
All my database calls now work through instantiating the PrismaService in the constructor of any service that may need it, and then simply make database calls through that.
After updating imports, run prisma generate manually. This step is no longer automatic after prisma migrate.
Simple and easy 🙂
Troubleshooting: Common Errors
The upgrade will likely surface errors. Here is a brief list of the ones I’ve encountered and how to fix them!
CI Fails: DATABASE_URL Not Found
Error: Environment variable not found: DATABASE_URL
It’s possible that CI will fail with some error about missing a environment variable DATABASE_URL, like the example above.
This happens because the env() call in prisma.config.ts, attempts to validate the provided environment variable, and if it isn’t found, it throws an error.
That also means it’s not possible to do something like this:
export default {
datasource: {
url: env('DATABASE_URL') ?? "some-other-value",
},
...
} satisfies PrismaConfig;
The solution is to instead explicitly provide the variable DATABASE_URL at build time for your CI.
That could for example be providing it as an ARG to your docker container:
ARG DATABASE_URL
ENV DATABASE_URL=$DATABASE_URL
RUN npx prisma generate
Or pass it directly:
DATABASE_URL="postgresql://dummy:dummy@localhost:5432/dummy" npx prisma generate
It is worth noting that env() simply reads the connection string to recognize which data it needs to generate the client for. Its entirely possible to provide a dummy value here, if preferable.
I would probably go with providing the actual value for the build step, but that’s just me 🙂
TypeScript TS2742 Errors in pnpm Monorepo
Error: The inferred type of 'DbNull' cannot be named without a reference to '@prisma/client-runtime-utils'
Why it happens: TypeScript can’t resolve types across pnpm’s node_modules structure in monorepo setups. This is a known issue with Prisma 7.
Workaround: Add explicit type annotations where the error occurs, or configure TypeScript to include the runtime utils path. In tsconfig.json:
{
"compilerOptions": {
"paths": {
"@prisma/client-runtime-utils": ["./node_modules/@prisma/client-runtime-utils"]
}
}
}
This issue is being tracked and should be resolved in a future release.
SSL Certificate Validation Errors
Error: Error: P1010: User was denied access on the database
Why it happens: Prisma 7 validates SSL certificates by default. The old Rust engine ignored invalid certificates. If your database uses self-signed certificates, connections will now fail.
Solution: Configure the adapter to accept the certificates:
const adapter = new PrismaPg({
connectionString: configService.get<string>('DATABASE_URL'),
ssl: {
rejectUnauthorized: false,
},
});
Be aware that disabling certificate validation has security implications. For production, consider properly configuring your database certificates instead.
Mapped Enum Runtime Errors
Error: Runtime error when using mapped enum values in create, update, or other operations.
Why it happens: There’s a bug where generated TypeScript types expect mapped values, but the Prisma Client engine expects schema names. If you use @map on enum values, this causes mismatches.
Workaround: Use the schema name as a string literal with type assertion:
await prisma.user.create({
data: {
status: 'ACTIVE' as any, // Schema name, not mapped value
},
});
Or remove @map directives from enums until the bug is fixed.
Module Not Found Errors
Error: Can't resolve './enums.js' or similar module resolution failures.
Why it happens: The generated client structure changed. Old import paths may no longer exist.
Solution: Delete the generated folder and regenerate:
rm -rf src/config/database/generated
npx prisma generate
Then update any imports that reference specific internal files.
Migration Results: What Changed
After completing the upgrade on a production NestJS application, here’s what I observed:
Bundle size: Dropped significantly. The Docker image shrank by several megabytes. Deploy times improved as a result.
Query performance: Difficult to measure precisely, but response times appeared marginally faster. The improvement is more noticeable on query-heavy operations.
Development experience: Mostly unchanged. The main difference is remembering to run prisma generate manually.
CI pipeline: Required configuration updates for the DATABASE_URL handling, but otherwise stable.
My honest is that the migration was more tedious than difficult.
Most of the time went into updating imports and debugging CI. The actual architectural change was straightforward once I understood what needed to change for the new config. It also can’t complain about having several codebases, that all needed this upgrade, across different setups and circumstances 🙂
Quick Reference Cheat Sheet
| Issue | Solution |
|---|---|
Environment variable not found: DATABASE_URL | Provide DATABASE_URL at build time in CI |
| TS2742 errors in pnpm monorepo | Add explicit type annotations or configure tsconfig paths |
| SSL certificate validation errors | Set ssl: { rejectUnauthorized: false } in adapter config |
| Mapped enum runtime errors | Use schema names with as any assertion |
| Module not found after upgrade | Delete generated folder and run prisma generate |
@prisma/client imports failing | Update imports to use generated folder path |
| Connection timeouts after upgrade | Configure explicit pool settings in adapter |
The upgrade process described here reflects my experience upgrading two separate codebases; one with a NestJS backend and one with a monorepo, both using PostgreSQL. Your specific setup may require additional configuration. The template repository provides a working reference implementation.