Setting Up Prisma with Supabase for Next.js
Intro
Prisma, Supabase, Next.js are all great, but there’s work to glue them together. In this blog, I will share the lessons I learned along the way.
For the official integration guide, check out Supabase’s Prisma documentation.
Getting Started: Installation
First, let’s install the necessary packages:
npm i -D prisma # prisma dev tooling
npm i @prisma/client # prisma client with TypeScript support
The prisma package provides CLI tools for schema management and migrations, while @prisma/client is the runtime query builder you’ll use in your application code.
Initializing Your Prisma Project
Run the initialization command:
npx prisma init
This single command sets up your entire Prisma project structure:
- Creates a
prismafolder at your project root—this becomes your schema definition home - Adds
DATABASE_URLto your.envfile with a default PostgreSQL connection string - Generates
prisma.config.tswith your project configuration
Tips:
- Create your
.envfile before runningnpx prisma initto avoid authentication prompts. - You will need to
npm i dotenvand addimport 'dotenv/configto theprisma.config.tsto load environment variables - thenpx prisma initscript does not add the import statement automatically for you.
The Next.js Gotcha: Singleton Pattern
If you’re coming from a traditional Node.js background, you might be tempted to instantiate Prisma like this:
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
Don’t do this in Next.js!
Next.js’s hot reloading in development will create multiple Prisma Client instances, potentially exhausting your database connections. Instead, implement the singleton pattern recommended in the Prisma Next.js documentation.
Here’s the code snippet:
import { PrismaClient } from "@prisma/client";
const globalForPrisma = global as unknown as { prisma: PrismaClient };
export const prisma = globalForPrisma.prisma || new PrismaClient();
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
export default prisma;
Supabase: Understanding Connection Methods
Here’s where things get interesting. Supabase offers multiple connection methods, and choosing the right one is crucial for serverless deployments.
Connection Method Overview
| Method | Best For |
|---|---|
| Direct | Server-based deployment |
| Transaction | Serverless deployment |
| Session | Serverless deployment |
Since we’re deploying serverless, we’ll use Transaction and the Session mode.
Configuration Details
| Method | Port | Environment Variable | Prisma Config | Notes |
|---|---|---|---|---|
| Transaction | 6543 | DATABASE_URL |
url |
Must append ?pgbouncer=true query param |
| Session | 5432 | DIRECT_URL |
directUrl |
Alternative to direct connection over IPv4 |
Key insight: The Transaction pooler (port 6543) routes through PgBouncer, which is essential for handling the ephemeral nature of serverless functions.
Running Your First Migration
Once your schema is defined, it’s time to sync it with your database:
npx prisma migrate dev --name init
Before running this, make sure you have:
- Installed dotenv:
npm i dotenv - Loaded environment variables in your schema file:
import 'dotenv/config'
Alternative approach: You could use npx prisma db push for quick prototyping, but never use this for production databases—it doesn’t create a migration history!
Patience with Cloud Instances
Fair warning: Supabase cloud instances can have delayed credential updates. Don’t panic if your first attempt fails—wait a minute and try again. Once successful, you’ll see a shiny new prisma/migrations folder tracking your database evolution.
Evolving Your Schema
When you need to update your schema (and you will), run migrations with descriptive names:
npx prisma migrate dev --name "fix-typo"
Good migration names are your future self’s best friend. “update schema” tells you nothing; “add-user-email-index” tells you everything.
The Client Generation Surprise
Here’s a gotcha that cost me an hour of debugging: Prisma 7.0 changed the default client provider.
Understanding Client Providers
| Provider | Version | Output Location |
|---|---|---|
prisma-client-js |
Prisma 6.x and earlier | ./node_modules/@prisma/client |
prisma-client |
Prisma 7.0+ | Configurable (e.g., @/lib/generated/prisma/client) |
The Autocomplete Mystery
I was importing from @prisma/client and wondering why I had no autocomplete for my models. Turns out, with Prisma 7.0+, the generated client lives in a custom location specified in your prisma.config.ts.
Solution: Import from your configured output location:
import { PrismaClient } from "@/lib/generated/prisma/client";
After switching to the correct import path, all my type safety and autocomplete came back. Beautiful!
Alternative: Change the provider back to prisma-client-js, and this will still have autocomplete enabled:
import { PrismaClient } from "@/prisma/client";
Key Takeaways
- Use Transaction and Session mode for serverless deployments with Supabase
- Implement the singleton pattern for Prisma Client in Next.js
- Write descriptive migration names for maintainability
- Check your Prisma version—7.0+ uses a different client provider
- Be patient with cloud credentials—they can take time to propagate
With this setup, you’ll have a type-safe, serverless-ready database layer that scales effortlessly. Happy coding!