Home / Articles

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.

Publisher: REACTAPP.TOP5 min read1112 words

This article is published in English.

Sources: Get Started With Prisma 7 with Nest Js & MySQL

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.
  1. 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
  1. Create the initial Prisma layout:
npx prisma init

That creates a prisma directory with:

  • schema.prisma — connection and models
  • prisma.config.ts — configuration
  • .env — typically database credentials
  1. Install a MySQL/MariaDB adapter (adapters are discussed again at the end):
 npm install @prisma/adapter-mariadb
  1. Configure URL, schema location, migration output, and seeds. Docs expect prisma.config.ts at the project root beside package.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.

  1. 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
}
  1. 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');
  }
}
  1. 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 {}
  1. 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();
  });
  1. Import PrismaModule into 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.