July 12, 2026


Reference: jb.desishub.com โ Prisma 7 + Next.js setup guide ยท Prisma documentation
This guide follows the same kind of setup used in this app: Next.js App Router, TypeScript, Prisma 7's new driver-adapter architecture, and a Postgres database โ with a choice of either Neon or Prisma's own managed Postgres.
Prisma 7 changed how the client connects to your database โ it now goes through a driver adapter (@prisma/adapter-pg for Postgres) instead of Prisma's older built-in query engine binary. This guide walks through the setup cleanly for both of the two most common free Postgres options right now: Neon and Prisma Postgres.
The important idea is this:
Prisma 7 needs three things working together: a
schema.prismafile describing your tables, aprisma.config.tsfile describing how to connect and migrate, and a driver adapter that actually talks to Postgres over the wire.
Once those three pieces agree with each other, everything else โ seeding, querying, server actions โ works the same regardless of which Postgres provider you chose.
By the end, you will have this:
app/
generated/
prisma/ # generated Prisma Client output
page.tsx
lib/
prisma.ts
prisma/
schema.prisma
seed.ts
prisma.config.ts
.envA working connection to either:
Neon โ a serverless Postgres branch
Prisma Postgres โ Prisma's own managed Postgres instanceBefore installing Prisma 7, make sure you already have:
prisma init)Prisma Postgres currently offers 5 free databases per account. Neon offers 10 free projects. Pick whichever fits your workflow โ both work identically once connected through Prisma 7's adapter.
Check which package manager you're using before continuing โ every command below is shown for both npm and pnpm.
If you're starting fresh:
pnpm create next-app@latest my-app
cd my-appSelect these options when prompted:
src directory (optional, either works with this guide)If you already have an existing Next.js 15+ project, just cd into it and continue from Step 2.
Prisma 7 splits its dependencies into dev tooling (prisma, tsx) and runtime packages (@prisma/client, the driver adapter, and the underlying pg driver).
pnpm add prisma tsx @types/pg --save-dev
pnpm add @prisma/client @prisma/adapter-pg dotenv pgWhat each package does:
prisma โ the CLI (generate, db push, studio, etc.)tsx โ runs TypeScript files directly, used for seeding@prisma/client โ the generated, type-safe query client@prisma/adapter-pg โ the Postgres driver adapter Prisma 7 requirespg โ the underlying node-postgres driver the adapter wrapsdotenv โ loads .env variables into prisma.config.tspnpm dlx prisma init --db --output ../app/generated/prismaThe --db flag provisions a free Prisma Postgres database automatically and writes its connection string straight into .env. If you'd rather use Neon instead, skip the --db flag:
pnpm dlx prisma init --output ../app/generated/prismaThis creates:
prisma/schema.prisma โ your database schemaprisma.config.ts โ Prisma 7's new configuration file.env โ with a placeholder or real DATABASE_URLapp/generated/prisma โ the output folder for your generated clientIf you initialized without --db, get your connection string from the Neon dashboard:
postgresql://user:password@ep-xxxx.region.aws.neon.tech/dbname?sslmode=require.env:DATABASE_URL="postgresql://user:password@ep-xxxx.region.aws.neon.tech/dbname?sslmode=require"Neon connection strings include
?sslmode=requireby default โ keep this, since Neon requires SSL connections.
Update prisma/schema.prisma:
generator client {
provider = "prisma-client"
output = "../app/generated/prisma"
}
datasource db {
provider = "postgresql"
}
model Category {
id String @id @default(cuid())
title String
slug String @unique
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}Notice the datasource block has no url field here โ in Prisma 7, the connection URL is supplied through prisma.config.ts instead of directly in schema.prisma. That's covered next.
prisma.config.tsThis file is new in Prisma 7 โ it replaces the old pattern of putting everything inside schema.prisma and environment variable magic.
import 'dotenv/config';
import { defineConfig, env } from 'prisma/config';
export default defineConfig({
schema: 'prisma/schema.prisma',
migrations: {
path: 'prisma/migrations',
},
datasource: {
url: env('DATABASE_URL'),
},
});What this does:
import 'dotenv/config' loads your .env file before Prisma reads anything โ without this, env('DATABASE_URL') returns undefined.datasource.url is where the actual connection string now lives, regardless of whether you're using Neon or Prisma Postgres.migrations.path tells Prisma where to store migration history if you use prisma migrate later.Prisma 7 documentation currently recommends
db pushovermigrate devfor early development โmigrate devhas known issues with the new config format at the time of writing. Usemigrate devonce your schema stabilizes and you want proper migration history.
pnpm dlx prisma db pushThen generate the Prisma Client:
pnpm dlx prisma generateThis writes the generated, type-safe client into app/generated/prisma, matching the output path set in Step 5.
Create lib/prisma.ts:
mkdir -p lib && touch lib/prisma.tsimport { PrismaClient } from '../app/generated/prisma/client';
import { PrismaPg } from '@prisma/adapter-pg';
const globalForPrisma = global as unknown as {
prisma: PrismaClient;
};
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL,
});
const db = globalForPrisma.prisma || new PrismaClient({ adapter });
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = db;
export default db;What this does:
PrismaPg is the driver adapter โ this is the Prisma 7 way of connecting, replacing the old built-in query engine.globalForPrisma pattern prevents Next.js's hot-reload in development from spinning up a new database connection on every file save.db for shorter, cleaner imports throughout your app.touch prisma/seed.tsimport db from '@/lib/prisma';
import { Prisma } from '../app/generated/prisma/client';
const categoriesData: Prisma.CategoryCreateInput[] = [
{ title: 'Electronics', slug: 'electronics' },
{ title: 'Fashion', slug: 'fashion' },
{ title: 'Home & Garden', slug: 'home-garden' },
{ title: 'Sports', slug: 'sports' },
];
export async function main() {
for (const cat of categoriesData) {
await db.category.create({ data: cat });
}
}
main();Register the seed command inside prisma.config.ts:
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: env('DATABASE_URL'),
},
});Run the seed:
pnpm dlx prisma db seedThen confirm the data landed with Prisma Studio:
pnpm dlx prisma studioimport db from '@/lib/prisma';
import Link from 'next/link';
export default async function Home() {
const categories = await db.category.findMany({
orderBy: { createdAt: 'desc' },
});
return (
<div className="min-h-screen bg-blue-50 p-8">
<div className="flex items-center justify-between py-6">
<h2 className="text-3xl font-semibold tracking-tight">Categories</h2>
</div>
<div className="grid grid-cols-1 gap-4 rounded bg-white p-8 md:grid-cols-2 lg:grid-cols-4">
{categories.map((category) => (
<Link
href={`/${category.slug}`}
key={category.id}
className="rounded border p-4 transition-colors hover:bg-gray-50"
>
{category.title}
</Link>
))}
</div>
</div>
);
}Run your dev server and confirm the seeded categories render:
pnpm devmkdir -p controllers/actions && touch controllers/actions/category.ts'use server';
import db from '@/lib/prisma';
import { revalidatePath } from 'next/cache';
export type CategoryFormData = {
name: string;
};
export async function createCategory(data: CategoryFormData) {
try {
const slug = data.name.toLowerCase().trim().split(' ').join('-');
await db.category.create({
data: { title: data.name, slug },
});
revalidatePath('/');
return { success: true, message: 'Category created successfully' };
} catch (error) {
console.log(error);
return { success: false, message: 'Failed to create category' };
}
}
export async function deleteCategory(id: string) {
try {
await db.category.delete({ where: { id } });
revalidatePath('/');
return { success: true, message: 'Category deleted successfully' };
} catch (error) {
console.log(error);
return { success: false, message: 'Failed to delete category' };
}
}Add a postinstall script so Prisma Client regenerates automatically after every install on your host (Vercel, a VPS, etc.):
{
"scripts": {
"dev": "next dev",
"build": "next build",
"postinstall": "prisma generate",
"start": "next start",
"lint": "next lint"
},
"prisma": {
"seed": "tsx prisma/seed.ts"
}
}When deploying, add DATABASE_URL as an environment variable on your host โ for Vercel, that's under Project Settings โ Environment Variables. Use your Neon connection string or your Prisma Postgres connection string, exactly as it appears in your local .env.
prisma/schema.prismaThis defines every table.
It answers:
prisma.config.tsThis is Prisma 7's new configuration entry point.
It answers:
lib/prisma.tsThis is the shared, type-safe client.
It answers:
prisma/seed.tsThis populates your database with starter data.
It answers:
prisma migrate dev fails or behaves unexpectedlyAt the time of writing, migrate dev has known issues with Prisma 7's new config format. Use db push during early development instead:
pnpm dlx prisma db pushenv('DATABASE_URL') returns undefinedprisma.config.ts doesn't automatically load .env โ make sure import 'dotenv/config'; is the very first line in the file.
Remove --turbopack from your dev script in package.json if you're pinned to one of those two exact versions:
{
"scripts": {
"dev": "next dev"
}
}Newer Next.js 15.x and 16.x releases don't have this issue.
Cannot find module '../app/generated/prisma/client'Run prisma generate again โ the generated client only exists after this command runs, and it needs to be re-run any time you change schema.prisma.
pnpm dlx prisma init --db --output ../app/generated/prisma # initialize with Prisma Postgres
pnpm dlx prisma db push # push schema
pnpm dlx prisma generate # generate client
pnpm dlx prisma db seed # seed database
pnpm dlx prisma studio # open Prisma StudioUse this checklist when setting up Prisma 7 in a Next.js 15+ project:
prisma, tsx, @types/pg as dev dependencies@prisma/client, @prisma/adapter-pg, dotenv, pg as dependenciesprisma init โ with --db for Prisma Postgres, without it for Neon.envprisma/schema.prismaprisma.config.ts with dotenv/config and your datasource URLprisma db push, then prisma generatelib/prisma.ts with the PrismaPg adapter singletonpostinstall script before deployingDATABASE_URL as an environment variable on your hostThe clean mental model is:
schema.prisma
-> prisma.config.ts (connection + migrations + seed)
-> prisma db push
-> prisma generate
-> lib/prisma.ts (PrismaPg adapter singleton)
-> your app's Server Components and Server ActionsWhether the actual database sits on Neon or Prisma Postgres makes almost no difference once you're past Step 6 โ both are just a DATABASE_URL pointing at a Postgres instance, and Prisma 7's driver adapter talks to either one identically.
The biggest advice is simple:
Use
db pushovermigrate devfor now, always loaddotenv/configat the top ofprisma.config.ts, and re-runprisma generateevery time your schema changes.