
Next.js App Routerが導入されたとき、それはフルスタックReact開発における根本的なパラダイムシフトを意味しました。React Server Components(RSC)とPrisma ORMを組み合わせることで、開発者はサーバーコンポーネントから直接データベースをクエリでき、クライアント側のフェッチウォーターフォールをゼロにし、完全なTypeScriptの安全性と、楽なServer Actionミューテーションを実現します。
この包括的なガイドでは、コネクションプーリング、プール枯渇を防ぐためのグローバルシングルトン、型安全なServer Actions、自動化されたデータベースシードスクリプトなど、本番環境に対応したNext.jsとPrismaアプリケーションを構築する方法を探ります。
Prismaをインストールし、データベース接続を初期化します。
npm install prisma @prisma/client
npx prisma init
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())
}
ローカル開発中、Next.js Fast Refreshはファイル編集ごとにNode.jsモジュールキャッシュをクリアします。個々のルートファイル内でnew PrismaClient()をインスタンス化すると、ホットリロードのたびに新しいデータベース接続が作成され、すぐにPostgreSQLのmax_connectionsエラーが発生します。
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
Server Componentsはサーバー上でのみ実行されるため、接続文字列を公開したり、中間APIルートを構築したりすることなく、Prismaを直接クエリできます。
// 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>
)
}
データをミューテーションするには、'use server'でServer Actionsを宣言し、キャッシュタグを再検証します。
// 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}`)
}
開発データベースをシードするには、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()
})
package.jsonにシードスクリプトの設定を追加します。
{
"prisma": {
"seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
}
}
npx prisma db seedでシードコマンドを実行します。
Next.js Fast Refreshはファイル変更ごとにモジュールを再構築し、ホットリロードのたびに新しいPrismaClientインスタンスを作成します。クライアントをNode.jsのグローバルオブジェクト(globalThis.prismaGlobal)にアタッチすることで、開発サーバーのライフサイクル中に単一の接続プールインスタンスのみが存在するようにします。
いいえ、Prismaはブラウザのランタイム内では実行できない直接的なTCPデータベースソケット接続を必要とします。Prismaのクエリは、Server Components、Route Handlers、またはServer Actions内でのみ実行してください。
VercelやAWS Lambdaのようなサーバーレスプラットフォームにデプロイする場合、PgBouncer、Neon Serverless Pooling、Supabase Supavisor、またはPrisma Accelerateと?pgbouncer=true&connection_limit=1のようなコネクションプーラーを介して接続します。
package.jsonにprisma/seed.tsを指すprisma.seedコマンドを定義し、npx prisma db seedを実行してデモデータを決定論的に投入します。
Next.js App RouterアプリケーションでPrismaを使用している場合、特にFast Refreshを使用したローカル開発中に、`PrismaClient`にグローバルシングルトンパターンを実装することがなぜ重要なのでしょうか?
AI CLIログの整形、Cron式の作成、JWTの解析、chmod権限の計算をオフラインで実行。

Next.js App Routerの包括的なプロダクションガイド:サーバーコンポーネントの境界、高度なキャッシング、Suspenseによるストリーミング、サーバーアクション、コネクションプーリング、およびエンタープライズ向けルートアーキテクチャ。
続きを読む
Next.jsでDuckDB-Wasmを使用し、本番環境レベルのアーキテクチャとコード例で1000万行に対する超高速クライアントサイド分析を実現する包括的なガイド。
続きを読む
PrismaとTypeScriptを使った最新のデータベースシーディング戦略を網羅的に解説。冪等性、Faker.js連携、複雑なリレーショナルデータの扱い、大規模なシードスクリプトのパフォーマンス最適化について探ります。
続きを読む