Next.js + Prisma 完整集成指南
项目初始化
Prisma 官方提供了 Next.js 脚手架:
npx create-prisma@latest my-next-app --template next --provider postgres --no-deploy
这会创建一个完整的 Next.js + Prisma 项目,包含:
prisma/schema.prisma(已配好 PostgreSQL datasource 和 Client generator)src/lib/prisma.ts(全局单例)- 一个简单的 CRUD 示例页面
.env(占位的 DATABASE_URL)
手动添加到现有 Next.js 项目
npm install prisma --save-dev
npm install @prisma/client
npx prisma init
PrismaClient 全局单例(开发热重载必备)
Next.js 开发模式用 HMR(热模块替换),每次文件变更会重新执行模块。这会导致每次热重载都创建一个新 PrismaClient 实例,连接池快速耗尽。
必须把 PrismaClient 做成全局单例:
// src/lib/prisma.ts
import { PrismaClient } from '@prisma/client'
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined
}
export const prisma =
globalForPrisma.prisma ??
new PrismaClient({
log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'],
})
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
然后在任何需要数据库的地方:
import { prisma } from '@/lib/prisma'
Server Components 里查询(App Router)
Next.js 13+ App Router 的 Server Components 天然支持 async/await,可以直接在组件里查询:
// app/users/page.tsx
import { prisma } from '@/lib/prisma'
import UserCard from './UserCard'
export default async function UsersPage() {
const users = await prisma.user.findMany({
include: { posts: true },
orderBy: { createdAt: 'desc' },
})
return (
<div>
<h1>用户列表</h1>
{users.map(user => (
<UserCard key={user.id} user={user} />
))}
</div>
)
}
Server Components 在服务器端执行,可以直接用 await prisma.user.findMany()。不需要 $connect()——Prisma Client 懒连接,第一次查询自动建立连接。
Server Actions 写入数据
Next.js Server Actions 是处理表单提交的推荐方式:
// app/actions.ts
'use server'
import { prisma } from '@/lib/prisma'
import { revalidatePath } from 'next/cache'
import { redirect } from 'next/navigation'
export async function createUser(formData: FormData) {
const email = formData.get('email') as string
const name = formData.get('name') as string
await prisma.user.create({
data: { email, name },
})
revalidatePath('/users')
redirect('/users')
}
// app/users/new/page.tsx
import { createUser } from '../actions'
export default function NewUserPage() {
return (
<form action={createUser}>
<input name="email" type="email" required />
<input name="name" />
<button type="submit">创建</button>
</form>
)
}
API Route 里用 Prisma
// app/api/users/route.ts
import { NextResponse } from 'next/server'
import { prisma } from '@/lib/prisma'
export async function GET() {
const users = await prisma.user.findMany()
return NextResponse.json(users)
}
export async function POST(request: Request) {
const body = await request.json()
const user = await prisma.user.create({ data: body })
return NextResponse.json(user, { status: 201 })
}
Vercel 部署注意
Vercel Serverless Functions 有以下特点:
- 函数冷启动:每次函数实例可能首次启动,Prisma Client 会首次建立连接
- 最大执行时长:免费版 10 秒、Pro 60 秒、Enterprise 可配置
- 并发执行:Vercel 会同时起多个函数实例,每个实例有独立的连接池
配置 Pre-build Command
在 Vercel 项目设置里:
- Build Command:默认
next build - Pre-build Command:
npx prisma migrate deploy(先跑迁移再构建) - Environment Variables:确保
DATABASE_URL和DIRECT_URL(生产数据库如果用了连接池)
Prisma Postgres 自动集成
如果用 Prisma Postgres(官方托管数据库),Vercel 可以直接自动注入环境变量——在 Vercel 项目设置里连一下就好,不需要手动配 DATABASE_URL。
连接池问题
如果数据库直连 Vercel 出现"连接过多"或握手超时:
- 确认用了
DIRECT_URL绕过连接池跑迁移 - 考虑用 Prisma Accelerate(官方连接池服务)或 PgBouncer
- 检查数据库的最大连接数设置
Next.js + Prisma 模板
Prisma 官方维护了几个 Next.js 示例仓库,覆盖常见场景(搜索 prisma-examples GitHub 仓库):
- TypeScript/nextjs 目录 — 基础集成
- rest-nextjs-api-routes 目录 — REST API 示例
- nextjs-fullstack 目录 — 完整全栈应用示例