Part 2: Build Your First Prisma Project from Scratch with PostgreSQL

In the first article, we got to know Prisma from a macro perspective. Now, in this one, we'll start directly from a real project: using Prisma 7 + Next.js 16.2.2 + PostgreSQL + pnpm, from an empty directory to "being able to see the first User record from the database on the page".
You will complete:
Create a Next.js 16.2.2 project (App Router);
Configure pnpm as the package manager;
Set up the PostgreSQL database;
Initialize Prisma 7 (including prisma.config.ts);
Define the first
Usermodel and migrate to the database;Use Prisma Client in a Next.js Server Component to query and render data.
Complete Command Overview (Quick Reference)
Here's a quick look at all the key commands used in this article:
# 1. Confirm / Install pnpm
corepack enable
corepack prepare pnpm@latest --activate
# 2. Create Next.js 16.2.2 project
pnpm create next-app@16.2.2 prisma-next-demo
cd prisma-next-demo
# 3. Install Prisma 7 + PostgreSQL dependencies
pnpm add -D prisma tsx @types/node @types/pg
pnpm add @prisma/client @prisma/adapter-pg pg dotenv
# 4. Initialize Prisma 7
pnpm prisma init
# 5. Generate and apply the first migration based on schema
pnpm prisma migrate dev --name init
# 6. Check migration status (optional)
pnpm prisma migrate status
# 7. Open Prisma Studio (visual data insertion)
pnpm prisma studio
# 8. Start Next.js development server
pnpm devThe main text will explain step by step what each command does.
1. Prepare Environment: Node.js, pnpm, PostgreSQL
1.1 Node.js and pnpm
Make sure you have Node.js installed (v18+ recommended), then enable pnpm via Corepack:
corepack enable
corepack prepare pnpm@latest --activate
pnpm -vIf you see a version number, pnpm is ready to use.
1.2 Prepare PostgreSQL
You can provide PostgreSQL in any way. Here's a common Docker example:
docker run -itd \
-e POSTGRES_USER=prisma \
-e POSTGRES_PASSWORD=prisma \
-e POSTGRES_DB=next_prisma_demo \
-p 5432:5432 \
--name next-prisma-postgres \
postgresOur conventions:
User:
prismaPassword:
prismaDatabase:
next_prisma_demoPort:
5432
The .env DATABASE_URL will be:
DATABASE_URL="postgresql://prisma:prisma@localhost:5432/next_prisma_demo?schema=public"If you're using a cloud PostgreSQL (Neon / Supabase / Railway / Prisma Postgres), simply replace the connection string.
2. Create Next.js 16.2.2 Project with pnpm
In your prepared directory, run:
pnpm create next-app@16.2.2 prisma-next-demo
cd prisma-next-demoIn the interactive guide, it's recommended to select:
TypeScript: Yes
ESLint: Yes
Tailwind CSS: Yes (it will make the UI much nicer later)
Use
src/directory: optional; the examples below assume no src, meaningapp/is at the root; nextjsApp Router: Yes
Import alias: Keep default
@/*.
After this step, you have a Next.js 16.2.2 App Router project skeleton.
3. Install Prisma 7 and PostgreSQL Dependencies
According to the official Prisma 7 Postgres Quickstart, we need: CLI + Client + PostgreSQL adapter + driver.
Run in the project:
pnpm add -D prisma tsx @types/node @types/pg
pnpm add @prisma/client @prisma/adapter-pg pg dotenvRole explanation:
prisma: CLI tool (pnpm prisma ...);@prisma/client: TypeScript client generated from schema;@prisma/adapter-pg: Prisma 7 recommended PostgreSQL driver adapter;pg: node-postgres driver;dotenv: reads.env;tsx: convenient for writing seed scripts later.
4. Initialize Prisma 7: Generate Config and Schema
Prisma 7 recommends using prisma init to generate a set of default configurations including prisma.config.ts.
Run in the project root:
pnpm prisma initAfter execution, you'll see these new files:
prisma/schema.prismaprisma.config.ts.env
These three files handle:
Schema: describes data models;
Config: tells the Prisma CLI about schema/migrations/datasource configuration;
.env: provides environment variables like
DATABASE_URL.
4.1 Configure .env DATABASE_URL
Open .env and fill in the connection string based on the PostgreSQL you prepared:
DATABASE_URL="postgresql://prisma:prisma@localhost:5432/next_prisma_demo?schema=public"If using Prisma Postgres, fill in the PostgreSQL connection URL provided in the Prisma console. Make sure it's in the postgresql:// format.
4.2 Configure prisma.config.ts
The configuration method given in the official Prisma Next.js guide is roughly as follows:
// prisma.config.ts
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'),
},
})This configuration explains:
Prisma CLI uses
prisma/schema.prismaas the schema file;Database migrations are stored in
prisma/migrations;The datasource URL is read from the environment variable
DATABASE_URL;Uses
dotenv/configto automatically load.env.
5. Write the First Prisma Schema: User Model
Open prisma/schema.prisma and change it to a minimal usable version:
// prisma/schema.prisma
generator client {
provider = "prisma-client"
output = "../generated/prisma"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
name String
email String @unique
createdAt DateTime @default(now())
}A few points here:
Using
provider = "prisma-client"with a customoutputdirectory../generated/prismais one of the recommended approaches in Prisma 7;datasource is explicitly set to
postgresql;Usermodel includes:Auto-increment Integer primary key
id;Simple string field
name;Unique constraint on
email;Auto-fill current time
createdAt.
All subsequent Prisma Client types and safety features originate from this schema.
6. Generate and Apply the First Migration (Development)
The official Prisma recommended workflow is: use migrate dev for development, and migrate deploy for production.
Run in the project root:
pnpm prisma migrate dev --name initIt will:
Generate a migration based on the current
schema.prismaand database state;Write the migration SQL into
prisma/migrations/*/migration.sql;Apply it to your PostgreSQL database;
Generate or update Prisma Client.
If successful, you can optionally check the migration status:
pnpm prisma migrate statusIt will show which migrations have been applied and whether the current database is in sync with the schema.
Production reminder (will be covered in detail later):
Usingmigrate devin development is fine, but in production, only usemigrate deployand put it into your CI/CD pipeline, not manually on the server.
7. Create a Prisma Client Singleton in Next.js
To use Prisma Client safely in Next.js (especially with hot reloading in development), the official Next.js guide recommends using a singleton pattern with an adapter.
Create a new file lib/prisma.ts in the project:
// lib/prisma.ts
import { PrismaClient } from '../generated/prisma'
import { PrismaPg } from '@prisma/adapter-pg'
const connectionString = process.env.DATABASE_URL
if (!connectionString) {
throw new Error('DATABASE_URL is not set')
}
const adapter = new PrismaPg({ connectionString })
const globalForPrisma = globalThis as unknown as {
prisma?: PrismaClient
}
export const prisma =
globalForPrisma.prisma ??
new PrismaClient({
adapter,
})
if (process.env.NODE_ENV !== 'production') {
globalForPrisma.prisma = prisma
}This code illustrates several key concepts:
Use the
PrismaPgadapter to connect Prisma Client to PostgreSQL;In development, attach the PrismaClient instance to
globalThisto avoid creating too many connections during hot reload;In production, create a single instance normally without polluting the global scope.
Throughout the project, you only need to import prisma from lib/prisma without creating a new instance again.
8. First Database Query on the Next.js Home Page
Next, we'll use Prisma to query the User table in app/page.tsx and render the results on the page.
Edit app/page.tsx:
// app/page.tsx
import { prisma } from '@/lib/prisma'
export default async function Home() {
const users = await prisma.user.findMany({
orderBy: { createdAt: 'desc' },
})
return (
<main style={{ padding: '32px' }}>
<h1>Prisma 7 + Next.js 16.2.2 + PostgreSQL</h1>
<p>Current number of users: {users.length}</p>
<ul>
{users.map((u) => (
<li key={u.id}>
{u.name} - {u.email}
</li>
))}
</ul>
</main>
)
}Since this is a Server Component (default), we can directly use await prisma.user.findMany in the function body. This is a very natural combination of Next.js App Router and Prisma.
The only problem now is that there is no user data in the database. We'll add one right away.
9. Insert the First User with Prisma Studio
Prisma Studio is the official Web UI to view and edit data directly in the browser.
Run in the project root:
pnpm prisma studioA browser interface will open. On the left side, you'll see the User table:
Click
User;Click "Add Record";
Fill in, for example:
name:
Aliceemail:
alice@example.com;
Save.
Back in the terminal, start the Next.js development server:
pnpm devOpen your browser and go to http://localhost:3000. You should see:
The title;
"Current number of users: 1";
A list item with
Alice - alice@example.com.
At this point, the full chain is working: Browser → Next.js App Router → Prisma Client → PostgreSQL → Return Data → Page Render.
10. Example package.json (Prisma + Next.js + pnpm)
For your reference, here is a typical package.json snippet (only showing relevant parts from this article). You can adjust as needed:
{
"name": "prisma-next-demo",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"prisma:generate": "prisma generate",
"prisma:migrate": "prisma migrate dev",
"prisma:deploy": "prisma migrate deploy",
"prisma:studio": "prisma studio"
},
"dependencies": {
"@prisma/adapter-pg": "^7.0.0",
"@prisma/client": "^7.0.0",
"dotenv": "^16.0.0",
"next": "16.2.2",
"pg": "^8.0.0",
"react": "18.3.1",
"react-dom": "18.3.1"
},
"devDependencies": {
"@types/node": "^22.0.0",
"@types/pg": "^8.0.0",
"prisma": "^7.0.0",
"tsx": "^4.0.0",
"typescript": "^5.0.0"
}
}You can adjust version numbers based on actual installation (
^7.0.0indicates Prisma 7 major version);Adding
prisma:migrate/prisma:deployscripts makes CI/CD calls more convenient.
11. Common Errors and Troubleshooting
11.1 Error: P1001 Cannot connect to database
Typical errors contain "The database server was reached but timed out" or "Cannot reach database server". Common causes:
Docker container not started / PostgreSQL not running;
.envDATABASE_URLis incorrect (username/password/database name/port);Database firewall rules restricting access (for remote cloud databases).
Troubleshooting suggestions:
Confirm Docker container is running:
docker ps;Use psql / a GUI tool to test the connection and verify the connection string;
Ensure the Next.js project and database are network-accessible to each other.
11.2 Error: DATABASE_URL is not set
In lib/prisma.ts, we explicitly check for process.env.DATABASE_URL and throw an error if missing.
Common causes:
.envfile not created;.envis in the wrong path (not the project root);The start command was not executed from the project root.
Troubleshooting suggestions:
Confirm
.envis in the same directory aspackage.json;Confirm you run
pnpm devfrom the project root;Restart the development server to reload environment variables.
11.3 relation "User" does not exist
This means the table does not exist in the database, but you have already called a query. Common cause: forgot to run migrate dev or migrate deploy.
Solution:
pnpm prisma migrate dev --name initThen restart pnpm dev.
11.4 Next.js Development: Too many connections / Warnings
If you frequently see Postgres errors like "too many clients already" during development, it's usually because PrismaClient is being instantiated multiple times, leading to connection pool accumulation.
Solution:
Ensure
lib/prisma.tsuses the global singleton pattern (globalThis.prisma);Make sure all imports use
import { prisma } from '@/lib/prisma', and no place manually doesnew PrismaClient.
12. Summary: After This Article, You Have an "Extensible" Project Starting Point
In this article, we deliberately set up Prisma from scratch within the Prisma 7 + Next.js 16.2.2 + pnpm + PostgreSQL stack, rather than in a standalone script project. This ensures that all future practical articles (Next.js, MCP, AI-assisted development) can connect seamlessly.
By now, you have:
A modern Next.js App Router project skeleton;
A PostgreSQL database with trackable migration history;
A Prisma 7-based Client singleton adapted for PostgreSQL;
The first type-safe database query from a page.
Reference Links
Prisma Documentation
https://www.prisma.io/docs/getting-started/prisma-orm/quickstart/postgresql
https://www.prisma.io/docs/guides/use-prisma-in-pnpm-workspaces
https://www.prisma.io/docs/orm/prisma-migrate/workflows/development-and-production
GitHub
Follow on Google
Add HeyBinyang as a preferred source on Google
If you'd like to keep finding my updates through Google, you can mark this site as a preferred source and make it easier to spot in relevant reading flows.
SHARE
Share
Share this article.