首页 / Prisma ORM 入门教程 / Next.js 全栈集成

Prisma ORM 入门教程

Next.js 全栈集成

本教程共 54 篇 · 第 48 篇 · 更新于 2026-08-11 · 约 5 分钟阅读

Next.jsApp RouterServer ComponentServer ActionsVercelHMR单例模式

本节目标:把 Prisma 接进 Next.js App Router 应用,学会单例写法、服务端查询和构建部署链路。

初始化项目与安装

Next.js 是全栈 React 框架,前后端代码放一起。用官方脚手架创建项目:

npx create-next-app@latest nextjs-prisma

按提示选择 TypeScript、App Router 即可。然后安装 Prisma 依赖:

npm install @prisma/client @prisma/adapter-pg dotenv pg
npm install --save-dev prisma tsx @types/pg
npx prisma init --output ../app/generated/prisma
Note

官方 Next.js 指南的 package.json 示例里还写着 @prisma/client ^6.2.1,那是 v6 残留。本教程统一使用 v7:prisma-client 生成器 + 必填 output + 驱动程序适配器。

lib/prisma.ts:单例防 HMR

Next.js 开发模式下热重载(HMR)会反复重新执行模块。每次重载都 new PrismaClient(),会不断新建连接池,几分钟就耗尽数据库连接。解决办法是把实例挂在全局对象上:

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

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

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL,
});

const prisma =
  globalForPrisma.prisma ??
  new PrismaClient({
    adapter,
  });

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

export default prisma;

开发环境复用全局实例,生产环境每次冷启动只建一次。这个文件就是全应用的数据库入口。

Server Component 直接查询

App Router 的 Server Component 天然支持 async。页面可以直接查数据库,不需要中间层:

// app/page.tsx
import prisma from "@/lib/prisma";

export default async function Home() {
  const users = await prisma.user.findMany();
  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

查询带关系也一样,include 一次拿全:

// app/posts/page.tsx
const posts = await prisma.post.findMany({
  include: { author: true },
});

详情页记得处理查不到的情况,调用 notFound() 渲染 404:

// app/posts/[id]/page.tsx
const { id } = await params;
const post = await prisma.post.findUnique({
  where: { id: parseInt(id) },
  include: { author: true },
});
if (!post) notFound();

写数据:API Routes 或 Server Actions

两种写路径。API Routes 适合对外提供接口,写法与 Express 路由类似:

// app/api/posts/route.ts
import { NextResponse } from "next/server";
import prisma from "@/lib/prisma";

export async function POST(request: Request) {
  const body = await request.json();
  const post = await prisma.post.create({
    data: { title: body.title, authorId: body.authorId },
  });
  return NextResponse.json(post, { status: 201 });
}

GET 路由同理。注意 Next.js 15 之后路由处理器默认不缓存,每次请求都拿最新数据:

// app/api/posts/route.ts
export async function GET() {
  const posts = await prisma.post.findMany({
    where: { published: true },
    orderBy: { createdAt: "desc" },
    take: 20,
  });
  return NextResponse.json(posts);
}

Server Actions 适合表单场景。函数标 "use server",提交后写入数据库并刷新页面缓存:

// app/posts/new/page.tsx
import Form from "next/form";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import prisma from "@/lib/prisma";

export default function NewPost() {
  async function createPost(formData: FormData) {
    "use server";
    await prisma.post.create({
      data: {
        title: formData.get("title") as string,
        authorId: 1,
      },
    });
    revalidatePath("/posts");
    redirect("/posts");
  }

  return (
    <Form action={createPost}>
      <input name="title" placeholder="标题" />
      <button type="submit">创建</button>
    </Form>
  );
}
Tip

revalidatePath 让列表页立刻显示新数据,否则 Next.js 可能继续返回缓存的旧页面。

构建链:postinstall 钩子

Vercel、Netlify 这类平台会缓存依赖。缓存命中时 npm install 不会真正执行,Prisma 的自动生成钩子被跳过,部署的就是过期的 Client。解决方法是显式把 prisma generate 加进脚本:

{
  "scripts": {
    "postinstall": "prisma generate",
    "build": "next build"
  }
}
Note

如果部署时报错 「Prisma has detected that this project was built on Vercel, which caches dependencies」,就是这个原因。postinstall 或把 prisma generate && 加在 build 命令前均可修复。

多数据库与 Monorepo

多租户应用需要按租户动态建 Client。用工厂函数接收配置,每次调用返回独立实例:

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

export function createPrismaClient(databaseUrl: string) {
  return new PrismaClient({
    adapter: new PrismaPg({ connectionString: databaseUrl }),
  });
}

注意管理动态实例的生命周期,用完显式 $disconnect(),否则连接池越积越多。

Monorepo 场景下,多个包共用一份 Schema。建议把 Schema 放进共享包(如 @myorg/db),Prisma 依赖装在仓库根目录避免版本冲突,生成脚本用 --schema 指定路径:

{
  "scripts": {
    "prisma:generate": "prisma generate --schema=./packages/db/schema.prisma"
  }
}

部署到 Vercel

Vercel 与 Next.js 同源,部署最顺。步骤:

  1. 推送代码到 GitHub 仓库,在 Vercel 导入项目。
  2. 在项目设置里配置环境变量 DATABASE_URL
  3. 确认 postinstall 已包含 prisma generate,触发部署。

每次部署会重新生成 Client,数据库结构变更用 CI 里的 prisma migrate deploy 应用(详见下一章)。预览环境记得单独配一个数据库,否则 PR 里的迁移会直接改生产库。

参考来源

  • Prisma 官方文档:Next.js 集成指南(guides/frameworks/nextjs.mdx)
  • Prisma 官方文档:Next.js 排障与最佳实践(orm/more/troubleshooting/nextjs.mdx)
  • HireNodeJS:Prisma ORM for Node.js Production Guide 2026