Prisma 7 with NestJS and MySQL driver adapters
Prisma 7 inside a NestJS global module with MySQL: the TypeScript client, prisma.config.ts and the MariaDB driver adapter, wired so every service shares one.
This article is published in English.
Prisma is an ORM for Node.js and TypeScript that manages schemas, relations, and typed queries. Prisma 7 changes the runtime shape: the client path is simpler in some ways and stricter in others. The focus here is the Prisma 7 wiring for a NestJS service talking to MySQL—not a full Nest scaffold from zero.
What are the changes?
- Prisma Client no longer ships native Rust binaries.
- The client path is rewritten in TypeScript and runs in ordinary JS runtimes.
- Generated client output lives in project source, not buried only under
node_modules. - Regenerating the client no longer requires restarting the dev server.
- A new Prisma config file appears.
- Every database needs a driver adapter.
- The generated client is database-agnostic: it cares about schema structure, not a baked-in engine binary.
- Prisma Studio continues via
npx prisma studio. - Mapped enums are supported.
- Install Prisma 7 packages:
npm install @prisma/client@7
npm install -D prisma@7
Prisma 7 does not load environment variables automatically. Add dotenv:
npm install dotenv
Example Node and npm versions used in the original setup notes:
node -v
v24.11.1
npm -v
11.6.2
- Create the initial Prisma layout:
npx prisma init
That creates a prisma directory with:
schema.prisma— connection and modelsprisma.config.ts— configuration.env— typically database credentials
- Install a MySQL/MariaDB adapter (adapters are discussed again at the end):
npm install @prisma/adapter-mariadb
- Configure URL, schema location, migration output, and seeds. Docs expect
prisma.config.tsat the project root besidepackage.json.
.env:
DATABASE_URL="mysql://test_user:test_password@localhost:3306/test_db"
prisma.config.ts:
// This file was generated by Prisma and assumes you have installed the following:
// npm install --save-dev prisma dotenv
import "dotenv/config";
import { defineConfig, env } from "prisma/config";
export default defineConfig({
schema: "prisma/schema.prisma",
migrations: {
path: "prisma/migrations",
seed: 'tsx prisma/seed.ts',
},
datasource: {
url: process.env.DATABASE_URL!
},
});
A common pitfall is PrismaConfigEnvError: Missing required environment variable: DATABASE_URL, or complaints that a datasource is required for prisma db push. One tracked discussion is prisma/prisma#28590.
- Set client output and define models in the schema:
generator client {
provider = "prisma-client"
output = "../src/generated/prisma"
moduleFormat = "cjs" //Matches Prisma's output format with NestJS's CommonJS runtime environment.
}
datasource db {
provider = "mysql"
}
// Example model
model user {
id Int @id @default(autoincrement())
email String @unique
name String?
password String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
- Wrap the client in a NestJS service that owns connect/disconnect:
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { PrismaClient } from '../src/generated/prisma/client';
import { PrismaMariaDb } from '@prisma/adapter-mariadb';
@Injectable()
export class PrismaService
extends PrismaClient
implements OnModuleInit, OnModuleDestroy
{
constructor() {
const adapter = new PrismaMariaDb(process.env.DATABASE_URL!);
super({ adapter, log: ['info', 'warn', 'error'] });
}
async onModuleInit() {
try {
await this.$connect();
await this.$queryRaw`SELECT 1`;
console.log('✅ Prisma connected to MySQL');
} catch (error) {
console.error('❌ Prisma connection error:', error);
throw error;
}
}
async onModuleDestroy() {
await this.$disconnect();
console.log('🔌 Prisma disconnected from MySQL');
}
}
- Export it from a global module:
import { Module, Global } from '@nestjs/common';
import { PrismaService } from './prisma.service';
@Global()
@Module({
providers: [PrismaService],
exports: [PrismaService],
})
export class PrismaModule {}
- Optional seed script for test data:
import { PrismaClient } from '../src/generated/prisma/client';
import { PrismaMariaDb } from '@prisma/adapter-mariadb';
import 'dotenv/config';
const adapter = new PrismaMariaDb(process.env.DATABASE_URL!);
const prisma = new PrismaClient({ adapter });
async function main() {
console.log('🌱 Starting database seeding...');
// Check if database already has data
const userCount = await prisma.user.count();
if (userCount > 0) {
console.log('⚠️ Database already contains data. Skipping seed.');
console.log(` Found ${userCount} users in the database.`);
return;
}
console.log('📭 Database is empty. Starting seed...');
// Hash password for users
const hashedPassword = 'test12345';
// Create users
const user1 = await prisma.user.create({
data: {
email: 'robot@gmail.com',
name: 'Mr Robot',
password: hashedPassword,
},
});
console.log('✅ Created users');
}
main()
.catch((e) => {
console.error('❌ Error during seeding:', e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});
- Import
PrismaModuleinto the root module:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './modules/auth/auth.module';
import { ConfigModule } from '@nestjs/config';
import { PrismaModule } from 'prisma/prisma.module';
@Module({
imports: [AuthModule, PrismaModule, ConfigModule.forRoot()],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
With the database running:
npx prisma generate
npx prisma db push
npx prisma db seed
npm run start:dev
Ignore generated output in git:
/src/generated
Example folder layout:
└── 📁backend
└── 📁prisma
├── prisma.module.ts
├── prisma.service.ts
├── schema.prisma
├── seed.ts
└── 📁src
└── 📁generated
└── 📁prisma
└── 📁modules
└── 📁auth
├── app.controller.spec.ts
├── app.controller.ts
├── app.module.ts
├── app.service.ts
├── main.ts
├── .env
├── .gitignore
├── .prettierrc
├── eslint.config.mjs
├── nest-cli.json
├── package-lock.json
├── package.json
├── prisma.config.ts
├── README.md
├── tsconfig.build.json
└── tsconfig.json
Browse data locally:
npx prisma studio
Driver adapters
Older Prisma Client relied on a Rust query engine that turned client calls into SQL and opened TCP connections with built-in drivers. Prisma 7 moves compilation into a JavaScript query compiler and removes those embedded drivers. JavaScript database drivers talk to the database; driver adapters translate between the compiler and those drivers. For MySQL/MariaDB, use the mariadb adapter. See the Prisma docs section on database driver adapters for the current matrix.
NestJS wiring benefits from a single shared client instance per process. Creating a new PrismaClient inside every request handler multiplies connections and makes transactions harder to reason about. The global module pattern above keeps one service visible to feature modules while still allowing tests to replace PrismaService with a fake.
When regenerating after schema edits, confirm the output path still matches the import used in prisma.service.ts. A mismatch between generator output and import paths is a common source of “cannot find module” failures after otherwise successful prisma generate runs. Keep moduleFormat aligned with how Nest compiles—CommonJS versus ESM mismatches surface as subtle runtime errors rather than clean compile failures.
That is enough to get Prisma 7 talking to MySQL from NestJS with adapters, config files, and a generated client under source control boundaries.