Home / Articles / Setting Up Prisma 7 in a Next.js 16 TypeScript Project

This article is published in English.

Setting Up Prisma 7 in a Next.js 16 TypeScript Project

Learn how to install, configure, and migrate Prisma 7 with PostgreSQL in a Next.js 16 app, then build a singleton client to avoid connection leaks.

991 words

This walkthrough shows how to wire up Prisma 7 inside a Next.js 16 app that talks to PostgreSQL, using TypeScript and pnpm as the package manager.

Step 1: Add the Prisma Packages

pnpm add prisma @prisma/client @prisma/adapter-pg
  • prisma — the command-line tool you'll use for running migrations, generating the client, and managing your schema.
  • @prisma/client — the generated client library that your application code will call directly.
  • @prisma/adapter-pg — the PostgreSQL driver adapter that Prisma 7 introduced for connecting to Postgres.

With these three packages installed, you're ready to bootstrap the Prisma setup.

Step 2: Bootstrap Prisma

pnpm dlx prisma init

Running this scaffolds the baseline files and folders you need to get started.

prisma.config.ts
prisma/
└── schema.prisma

Understanding prisma.config.ts

This file holds the settings Prisma needs to operate, including how it connects to your database and how the client generator behaves.

import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
    schema: "prisma/schema.prisma",
    migrations: {
        path: "prisma/migrations",
    },
    datasource: {
        url: process.env["DATABASE_URL"],
    },
});

Understanding schema.prisma

Any table you plan to store in PostgreSQL will show up here eventually as a model definition.

generator client {
  provider = "prisma-client"
  output   = "../lib/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

// models that You want to create

Step 3: Point Prisma at Your Database

Prisma needs a connection string before it can talk to your database at all. You can obtain one from a hosted provider such as Neon, or by running a Postgres instance locally through Docker.

DATABASE_URL="postgresql://username:password@localhost:5432/my_database"

As soon as this environment variable is set, Prisma is able to reach your database.

Step 4: Define an Initial Model

Prisma Client can't be generated until at least one model exists in the schema.

Because the database is still empty at this point, add a minimal placeholder model just to give Prisma something to work with.

model Test {
  id Int @id @default(autoincrement())
}

The goal here isn't a meaningful table — it's just giving the generator a valid schema to build from.

Step 5: Apply Your First Migration

Next, turn that schema into real database tables by running a migration.

pnpm dlx prisma migrate dev

This single command handles a few things automatically:

  • It generates a new migration file.
  • It applies that migration against your configured database.
  • It keeps your live database structure in sync with what's declared in schema.prisma.

Once it finishes successfully, the Test table will exist in your database.

Step 6: Generate the Prisma Client

One of the more notable shifts in Prisma 7 is that the client is no longer generated for you automatically.

You now have to trigger generation explicitly.

pnpm dlx prisma generate dev

After this finishes, Prisma produces a fully typed client tailored to your schema.

That client exposes every method you'll need for querying and mutating your data.

generated/
└── prisma/

Each model defined in your schema is now exposed as its own typed TypeScript API.

Step 7: Build a Singleton Prisma Client

Rather than instantiating a new Prisma Client on every request, best practice is to reuse a single shared instance across your app.

File: lib/prisma.ts
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "./generated/prisma/client";

const globalForPrisma = globalThis as unknown as {
    prisma: PrismaClient | undefined;
};

function createPrismaClient() {
    const url = process.env.DATABASE_URL;
    if (!url) {
        throw new Error("DATABASE_URL is not set");
    }

    const adapter = new PrismaPg({ connectionString: url });
    return new PrismaClient({ adapter });
}

export const prisma = globalForPrisma.prisma ?? createPrismaClient();

if (process.env.NODE_ENV !== "production") {
    globalForPrisma.prisma = prisma;
}

Why a Singleton Matters Here

Next.js hot-reloads modules constantly while you're developing.

If a fresh PrismaClient gets created on every reload, you end up opening far more database connections than you intend to.

Left unchecked, this eventually surfaces as an error along these lines:

Too many database connections

Using the Singleton pattern guarantees that a single Prisma Client instance persists for the lifetime of the application.

This is the approach Prisma itself recommends for Next.js projects.

Step 8: Use the Client Throughout Your App

With the shared client instance in place, you can import it from anywhere in your project.

import { prisma } from "@/lib/prisma";

From here, any server component, API route, or server action has direct access to your database.

For further detail on this setup, consult the official Prisma documentation for Next.js integration, available at prisma.io/docs/guides/nextjs.