Next.js App Router với Prisma: Thiết lập & Kết nối Pooling

Table of Contents
Chuỗi kiến trúc Next.js hiện đại
Khi Next.js App Router được giới thiệu, nó đại diện cho một sự thay đổi mô hình cơ bản trong phát triển React full-stack. Bằng cách kết hợp React Server Components (RSC) với Prisma ORM, các nhà phát triển có thể truy vấn cơ sở dữ liệu trực tiếp từ các server component mà không có thác nước tìm nạp phía client, an toàn TypeScript hoàn toàn và các đột biến Server Action dễ dàng.
Trong hướng dẫn toàn diện này, chúng ta sẽ khám phá cách kiến trúc một ứng dụng Next.js và Prisma sẵn sàng cho sản xuất, bao gồm kết nối nhóm (connection pooling), các singleton toàn cục để ngăn chặn cạn kiệt nhóm, Server Actions an toàn kiểu (type-safe), và các script khởi tạo cơ sở dữ liệu tự động.
1. Khởi tạo dự án & Prisma Schema
Cài đặt Prisma và khởi tạo kết nối cơ sở dữ liệu của bạn:
npm install prisma @prisma/client
npx prisma init
Xác định các mô hình quan hệ của bạn bên trong prisma/schema.prisma:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
email String @unique
name String?
posts Post[]
createdAt DateTime @default(now())
}
model Post {
id String @id @default(cuid())
title String
content String?
published Boolean @default(false)
authorId String
author User @relation(fields: [authorId], references: [id])
createdAt DateTime @default(now())
}
2. Ngăn chặn cạn kiệt nhóm kết nối (Global Singleton)
Trong quá trình phát triển cục bộ, Next.js Fast Refresh xóa bộ nhớ cache mô-đun Node.js trên mỗi lần chỉnh sửa tệp. Nếu bạn khởi tạo new PrismaClient() bên trong các tệp route riêng lẻ, mỗi lần hot reload sẽ tạo các kết nối cơ sở dữ liệu mới, nhanh chóng gây ra lỗi PostgreSQL max_connections.
Tạo một singleton mạnh mẽ trong lib/prisma.ts:
// lib/prisma.ts
import { PrismaClient } from '@prisma/client'
const prismaClientSingleton = () => {
return new PrismaClient({
log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'],
})
}
declare global {
var prismaGlobal: undefined | ReturnType<typeof prismaClientSingleton>
}
const prisma = globalThis.prismaGlobal ?? prismaClientSingleton()
export default prisma
if (process.env.NODE_ENV !== 'production') globalThis.prismaGlobal = prisma
3. Tìm nạp dữ liệu trực tiếp trong React Server Components
Vì Server Components chỉ thực thi trên máy chủ, bạn có thể truy vấn Prisma trực tiếp mà không cần tiết lộ chuỗi kết nối hoặc xây dựng các route API trung gian:
// app/posts/page.tsx
import prisma from '@/lib/prisma'
import Link from 'next/link'
export const revalidate = 3600 // Cache page for 1 hour
export default async function PostsPage() {
const posts = await prisma.post.findMany({
where: { published: true },
include: { author: { select: { name: true, email: true } } },
orderBy: { createdAt: 'desc' },
})
return (
<main className="max-w-4xl mx-auto p-8">
<h1 className="text-3xl font-bold mb-6">Published Articles</h1>
<div className="grid gap-4">
{posts.map((post) => (
<article key={post.id} className="p-5 border rounded-xl shadow-sm">
<h2 className="text-xl font-semibold">{post.title}</h2>
<p className="text-sm text-gray-500">By {post.author.name}</p>
</article>
))}
</div>
</main>
)
}
4. Đột biến dữ liệu an toàn kiểu với Server Actions
Để đột biến dữ liệu, khai báo Server Actions với 'use server' và xác thực lại các thẻ cache:
// app/actions/createPost.ts
'use server'
import prisma from '@/lib/prisma'
import { revalidatePath } from 'next/cache'
import { redirect } from 'next/navigation'
export async function createPost(formData: FormData) {
const title = formData.get('title') as string
const content = formData.get('content') as string
const authorId = formData.get('authorId') as string
if (!title || !authorId) {
throw new Error('Title and Author are required')
}
const post = await prisma.post.create({
data: { title, content, published: true, authorId },
})
revalidatePath('/posts')
redirect(`/posts/${post.id}`)
}
5. Khởi tạo cơ sở dữ liệu tự động
Để khởi tạo cơ sở dữ liệu phát triển của bạn, hãy tạo prisma/seed.ts:
// prisma/seed.ts
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function main() {
await prisma.post.deleteMany()
await prisma.user.deleteMany()
const user = await prisma.user.create({
data: {
email: 'admin@locionic.com',
name: 'Locionic',
posts: {
create: [
{ title: 'Next.js App Router Architecture', published: true },
{ title: 'Prisma Connection Pooling Guide', published: true },
],
},
},
})
console.log('Database seeded successfully:', user.email)
}
main()
.catch((e) => {
console.error(e)
process.exit(1)
})
.finally(async () => {
await prisma.$disconnect()
})
Thêm cấu hình script khởi tạo vào package.json của bạn:
"prisma": {
"seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
}
Chạy lệnh khởi tạo với npx prisma db seed.
Next.js Fast Refresh xây dựng lại các mô-đun trên mỗi lần thay đổi tệp, tạo một phiên bản PrismaClient mới trên mỗi lần hot reload. Gắn client vào đối tượng toàn cục của Node.js (globalThis.prismaGlobal) đảm bảo chỉ có một phiên bản nhóm kết nối tồn tại trong suốt vòng đời của máy chủ phát triển.
Không, Prisma yêu cầu kết nối socket cơ sở dữ liệu TCP trực tiếp không thể chạy bên trong môi trường trình duyệt. Truy vấn Prisma độc quyền bên trong Server Components, Route Handlers hoặc Server Actions.
Khi triển khai lên các nền tảng serverless như Vercel hoặc AWS Lambda, hãy kết nối thông qua một bộ kết nối nhóm như PgBouncer, Neon Serverless Pooling, Supabase Supavisor hoặc Prisma Accelerate với ?pgbouncer=true&connection_limit=1.
Xác định lệnh prisma.seed trong package.json trỏ đến prisma/seed.ts, sau đó chạy npx prisma db seed để điền dữ liệu demo một cách xác định.
Bạn cũng có thể thích
- Cấu trúc thư mục Next.js App Router: Các phương pháp hay nhất & Kiến trúc doanh nghiệp (2026)
- React Testing Library user-event v14: Các phương pháp hay nhất & Di chuyển fireEvent (2026)
- Tăng tốc React với Rust và WebAssembly: Hướng dẫn toàn diện
- Rust cho các nhà phát triển Frontend: Hướng dẫn chuyển đổi thực tế
Free In-Browser Developer Tools
Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.
Related Articles

Lỗi Hydration trong Next.js: Cách sửa "Text Content Mismatch" & Error 418 (2026)
Hướng dẫn sửa triệt để lỗi Hydration failed (#418), Text content does not match server-rendered HTML, lỗi dark mode flash next-themes và localStorage trong Next.js.
Read more
Cách tôi xây dựng Portfolio của mình với Next.js, Contentlayer và Git Submodules
Phân tích kiến trúc của locionic.com: Next.js App Router, MDX an toàn kiểu Contentlayer, tối ưu hóa payload RSC và lưới liên kết nội bộ tự động.
Read more
suppressHydrationWarning trong Next.js: Hướng dẫn sử dụng an toàn & gỡ lỗi đầy đủ
Hướng dẫn toàn diện về suppressHydrationWarning trong Next.js: sử dụng an toàn & gỡ lỗi đầy đủ với các ví dụ thực tế đã được kiểm chứng.
Read more