はじめに
本記事では、TypeScript 向けの ORM(Object-Relational Mapping)である Prisma の使い方を解説します。
お問い合わせフォームを題材にし、Next.js の Server Actions 機能を用いて、サーバーサイドで SQLite データベースにアクセスする構成のデモ形式で進めます。
開発環境
- Node.js v20.11.1 以上
- npm v9.x 以上
Prisma のインストール
以下のコマンドを実行して、Prisma および Prisma Client をインストールします。
今回はバージョン6を指定します。
npm install prisma@^6
npm install @prisma/client@^6
Prisma の初期設定
以下のコマンドを実行して、初期設定を行います。
npx prisma init
実行後、プロジェクトのフォルダ直下に .env
ファイルと prisma/schema.prisma
ファイルが作成されます。
デモ構成について
このデモでは、src/prisma
配下に SQLite ベースのお問い合わせフォーム用データベースを作成し、Next.js の Server Actions から操作できるようにします。
1. SQLite の設定
このデモでは、開発用のファイルベースデータベースである「SQLite」を使用します。
まず、.env
にデータベースの URL を設定します。
データベース名は contact-form.db
とします。
CONTACT_DATABASE_URL="file:./contact-form.db"
続いて、schema.prisma
を編集します。
役割を明確にするために、src/prisma/contact-form
フォルダを作成し、初期の schema.prisma
をコピーして使用します。
以下のように設定します。
datasource db {
provider = "sqlite"
url = env("CONTACT_DATABASE_URL")
}
2. テーブルの設定
ContactForm
テーブルを作成します。テーブルの構成は以下のとおりです。
カラム名 | データ型 | 制約 |
---|---|---|
id | String | 主キー、デフォルト値あり |
userName | String | |
String | 重複不可 | |
createdAt | DateTime | デフォルト値あり |
schema.prisma
ファイルでの定義は以下のようになります。
model ContactForm {
id String @id @default(cuid()) // 主キー、デフォルト値
userName String
mail String @unique // 重複不可
createdAt DateTime @default(now()) // 作成日時に現在時刻を設定
}
3. テーブルの作成
以下のコマンドを実行し、Prisma スキーマに書いたモデル定義を、実際のデータベース(SQLite など)に反映させます。
npx prisma migrate dev --schema=prisma/contact-form/schema.prisma
この操作により、./migrations/(実行日時)_init
と contact-form.db
ファイルが作成されます。
開発環境では migrate dev を使い、本番環境では migrate deploy を使います。
また、今回のデモでは別途フォルダを作成して schema.prisma
がプロジェクトに2つある状態なので、 --schema
オプションをつけています。
デフォルトの src/prisma/schema.prisma
の1つだけであれば、オプションは不要です。
作成されたデータベースを GUI 上で確認するには、以下のコマンドを使用します。
npx prisma studio --schema=prisma/contact-form/schema.prisma
「http://localhost:5555/」で Prisma Studio が起動し、テーブルの内容を視覚的に確認できます。
4. PrismaClient の設定
TypeScript から Prisma を操作するために、PrismaClient
を生成します。
ジェネレーターの output
は src/generated/prisma/client/contact-form
に設定します。
generator client {
provider = "prisma-client-js"
output = "/src/generated/prisma/client/contact-form"
}
以下のコマンドで PrismaClient を生成します。
npx prisma generate --schema=prisma/contact-form/schema.prisma
5. Next.js の Server Actions で DB にアクセスする
まず、src/lib/contact-form/prisma.ts
を作成します。
以下のコードは、Prisma の公式ドキュメント「Prevent hot reloading from creating new instances of PrismaClient」に掲載されている例を基にしています。
// PrismaClient の型定義をインポート
import { PrismaClient } from "@/generated/prisma/client/contact-form";
// グローバルオブジェクトに prisma プロパティを追加
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };
// 既存インスタンスがあれば再利用し、なければ新規作成
export const prisma = globalForPrisma.prisma || new PrismaClient();
// 開発環境ではインスタンスをグローバルに保持
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
注意:
PrismaClient は generated/prisma/client/contact-form
に生成した型定義を参照させます。
Prisma v6.6.0 以降では、ESM 対応のジェネレーターが導入されており、@prisma/client
から直接インポートすると PrismaClient: any
となってしまう場合があります。必ず output
に設定したパスからインポートしてください。
次に、Server Actions で PrismaClient を使用してデータベースにアクセスするコードを実装します。
"use server";
import { redirect } from "next/navigation";
import { prisma } from "../contact-form/prisma";
export const submitForm = async (formData: FormData) => {
const userName = formData.get("userName") as string;
const mail = formData.get("mail") as string;
// メールアドレスの存在確認
const existRecord = await prisma.contactForm.findUnique({
where: { mail },
});
if (existRecord) {
return {
success: false,
error: {
mail: ["このメールアドレスは既に使用されています"],
},
};
}
// データベースに登録
await prisma.contactForm.create({
data: { userName, mail },
});
// 完了ページにリダイレクト
redirect("/complete");
};
メールアドレスの重複を確認し、既に存在していればエラーを返します。
存在しない場合は、フォームデータをデータベースに登録し、完了ページに遷移します。
まとめ
本記事では、Prisma を用いて Next.js の Server Actions からデータベース操作を行う方法を紹介しました。
Prisma を導入することで、
- DB が設計通りになる(schema.prisma に書いた model の定義をもとに自動作成されるため)
- TypeScript で型付き DB アクセスができるようになる
といったメリットが得られ、型安全かつ効率的にデータベース管理が可能になることを確認できました。