はじめに
本記事では、Prisma をプロジェクトに追加する方法と、スキーマ定義や使い方について解説します。
Prisma は、TypeScript 向けの ORM(Object-Relational Mapping)です。
開発環境
- Node.js v20.11.1 以上
- npm v9.x 以上
Prisma の初期設定
Prisma をプロジェクトに追加する際の初期設定を行います。
カレントディレクトリをプロジェクトフォルダに変更(例:cd my-project
)し、以下のコマンド操作を進めます。
インストール
Prisma の依存関係をインストールします。
npm install prisma@^6 @prisma/client@^6
- prisma@^6:Prisma CLI。マイグレーションやモデルの生成などを行う開発用ツール。
- @prisma/client@^6:アプリケーションから DB アクセスするための Prisma クライアント。
初期化
以下のコマンドを実行すると、prisma/schema.prisma
と .env
が生成されます。
npx prisma init
DB に sqlite を使用する場合、以下の通り設定します。
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
DATABASE_URL="file:./dev.db"
Prisma モデルの設定
prisma/schema.prisma
に Prisma モデルを記述します。
それぞれの定義内容を順番に見ていきます。
Prisma モデル: User
1. スキーマ定義
model User {
id String @id @default(cuid())
email String @unique
password String
userName String
posts Post[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
2. 定義詳細
フィールド名 | 日本語名 | 型 | 属性 | 制約 |
---|---|---|---|---|
id |
ユーザー ID | String |
@id @default(cuid()) |
主キー、自動生成 |
email |
メールアドレス | String |
@unique |
一意制約 |
password |
パスワード | String |
なし | 必須 |
userName |
ユーザー名 | String |
なし | 必須 |
posts |
投稿一覧 | Post[] |
リレーション | 1 対多関係 |
createdAt |
作成日時 | DateTime |
@default(now()) |
自動設定 |
updatedAt |
更新日時 | DateTime |
@updatedAt |
自動更新 |
補足説明:
-
@id
: 主キー(Primary Key)を示す。 -
@default(...)
: デフォルト値。cuid()
は一意な文字列を生成する。 -
@unique
: 一意制約。重複を許さない。 -
@updatedAt
: レコードが更新されるたびに、このフィールドが自動で更新される。 -
[]
: 他のモデルとの 1 対多のリレーション(外部キー制約)を示す。
Prisma モデル: Post
1. スキーマ定義
model Post {
id String @id @default(cuid())
title String
content String
topImage String?
published Boolean @default(true)
authorId String
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
2. 定義詳細
フィールド名 | 日本語名 | 型 | 属性 | 制約 |
---|---|---|---|---|
id |
投稿 ID | String |
@id @default(cuid()) |
主キー、自動生成 |
title |
タイトル | String |
なし | 必須 |
content |
本文 | String |
なし | 必須 |
topImage |
アイキャッチ画像 | String? |
なし | 任意(null 許容) |
published |
公開フラグ | Boolean |
@default(true) |
デフォルト: true
|
authorId |
著者 ID | String |
なし | 必須 |
author |
著者 | User |
@relation(fields: [authorId], references: [id], onDelete: Cascade) |
リレーション、削除連鎖 |
createdAt |
作成日時 | DateTime |
@default(now()) |
自動設定 |
updatedAt |
更新日時 | DateTime |
@updatedAt |
自動更新 |
3. 外部キー制約の説明
author
の属性は以下のように定義しています。
@relation(fields: [authorId], references: [id], onDelete: Cascade)
このアノテーションは、
モデル Post
にある authorId
は、
モデル User
の id
を参照しており、
もしその User
が削除されたら、紐づく Post
も 自動的に削除される(Cascade)
というリレーションです。
オプション | 説明 |
---|---|
fields: [authorId] |
現在のモデル(この場合 Post )で外部キーとして使うフィールドを指定します。このフィールドが、他のモデルの主キー等と一致する値を保持します。 |
references: [id] |
リレーション先のモデル(この場合 User )の、対応するフィールド(通常は主キー)を指定します。 |
onDelete: Cascade |
リレーション先(この場合 User )のデータが削除された時の動作を定義します。この場合は「連動して Post も削除される」という設定です。 |
この定義により、以下のことが保証されます:
-
Post
のauthorId
は、必ず存在するUser.id
に一致する必要がある(外部キー制約)。 - ある
User
を削除すると、そのユーザーが書いたすべてのPost
も自動的に削除される(Cascade)。
Prisma + Next.js でブログ記事一覧を取得する(Demo)
Next.js プロジェクトで Prisma を使って、以下の内容を実践します
- Prisma クライアントの設定
- スキーマの作成とマイグレーション
- ダミーデータ(seed)の挿入
- Prisma Studio を使ったデータ確認
- データベースからデータを取得して画面に表示
プロジェクトの構成は以下の通りです。
my-project/
├── prisma/
│ ├── data/
│ │ └── dummyData.js
│ ├── schema.prisma
│ └── seed.cjs
└── src/
├── app/
│ ├── globals.css
│ └── blog/
│ └── page.tsx
└── lib/
└── prisma.ts
1. Prisma Client の設定
まずは Prisma のクライアントを設定します。
// PrismaClient の型定義をインポート
import { PrismaClient } from "@/generated/prisma";
// グローバルオブジェクトに 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;
Next.js の開発環境では、ホットリロード時に PrismaClient が複数生成されるのを防ぐため、グローバルにインスタンスを保持するのが一般的です。
2. Prisma スキーマの設定
Prisma クライアントを src/generated/prisma に出力するよう指定します。
generator client {
provider = "prisma-client-js"
output = "../src/generated/prisma"
}
3. シードスクリプト(ダミーデータ挿入)
ダミーデータを挿入する seed.cjs スクリプトです。
// Prisma Client を読み込む(Prisma を使って DB にアクセスするためのライブラリ)
const { PrismaClient } = require("../src/generated/prisma");
// パスワードをハッシュ化するためのライブラリ(bcryptjs)
const bcrypt = require("bcryptjs");
// ダミーデータ
const { DUMMY_PASSWORD, USER_DATA, POST_DATA } = require("./data/dummyData");
const prisma = new PrismaClient(); // Prisma Client インスタンス
async function seed() {
// 既存データを削除(クリーンアップ)
await prisma.post.deleteMany(); // 投稿データを全削除
await prisma.user.deleteMany(); // ユーザーデータを全削除
// パスワードをハッシュ化
const password = await bcrypt.hash(DUMMY_PASSWORD, 12);
// ユーザー+投稿を一括作成
const user = await prisma.user.create({
data: {
...USER_DATA,
password,
posts: {
create: POST_DATA,
},
},
});
console.log("Seeded user:", user);
}
seed()
.catch((error) => {
console.error("Seeding failed:", error);
process.exit(1); // 終了コード1でプロセス終了
})
.finally(async () => {
await prisma.$disconnect(); // Prisma クライアントを閉じる(リソース解放)
});
シードスクリプトを .cjs
で作成する理由
Node.js では、ファイルの拡張子によってモジュールの扱いが変わります。
拡張子を .js
にすると、デフォルトでは ES モジュール(ESM) として解釈されることがあります(特に type: "module" が package.json にある場合)。
拡張子を .cjs
にすると、CommonJS モジュールとして明示的に扱われます。
Prisma の seed スクリプトは、初期状態では CommonJS 形式で動作する前提のため、拡張子を .cjs
にしてトラブル回避しています。
4. package.json に seed スクリプトを追加
"prisma": {
"seed": "node prisma/seed.cjs"
}
5. DB セットアップとダミーデータ挿入を実行
以下のコマンドを順番に実行することで、データベースのセットアップとダミーデータの挿入が完了します。
# Prisma スキーマをもとにマイグレーション(テーブル作成)
npx prisma migrate dev --name init
# Prisma クライアントの生成
npx prisma generate
# ダミーデータの挿入(seed)
npx prisma db seed
# Prisma Studio で DB 内容をGUI確認
npx prisma studio
6. データベースからデータを取得して画面に表示
データベースに保存された Post の内容を取得し、画面に表示します。
import { prisma } from "@/lib/prisma";
const BlogContents = async () => {
// データベースから全ての投稿を取得
const contents = await prisma.post.findMany({
orderBy: { createdAt: "desc" },
include: { author: true }, // リレーション先の投稿者情報も取得
});
return (
<>
<div className="overflow-x-auto">
<p>ブログ記事一覧</p>
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-100">
<tr>
<th className="th-style">タイトル</th>
<th className="th-style">内容</th>
<th className="th-style">著者</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{contents.map((content, index) => (
<tr key={index} className="hover:bg-gray-50">
<td className="td-style">{content.title}</td>
<td className="td-style">{content.content}</td>
<td className="td-style">
{content.author.userName}/{content.author.email}
</td>
</tr>
))}
</tbody>
</table>
</div>
</>
);
};
export default BlogContents;
http://localhost:3000/blog にアクセスすると、作成したダミーデータが画面に表示されていることが確認できます。
(補足)スタイリングとダミーデータの中身
この記事の本題は Prisma の使い方ですが、画面表示やシード作成に使った CSS クラスやダミーデータの中身についても、参考として簡単に紹介しておきます。
Tailwind CSS のカスタムクラス定義
Tailwind CSS のユーティリティクラスを同じ要素に繰り返し適用している場合、共通化の方法がいくつか用意されています。
今回は globals.css
に @apply
ディレクティブを使ってカスタムクラスを定義し、<th>
タグと <td>
タグに設定しています。
@import "tailwindcss";
.th-style {
@apply px-6 py-3 text-left text-xs font-medium text-gray-500;
}
.td-style {
@apply px-6 py-4 whitespace-nowrap text-sm text-gray-900;
}
ダミーデータの中身
シードスクリプトで使っているダミーデータです。
// ユーザーパスワード
const DUMMY_PASSWORD = "p@ssw0rd1234";
// メールアドレスとユーザー名
const USER_DATA = {
email: "test@example.com",
userName: "nanashi",
};
// 投稿データ
const POST_DATA = [
{
title: "Prismaとは",
content: "TypeScript 向けの ORM(Object-Relational Mapping)",
},
{
title: "Next.js の Server Actions について",
content: "Server Actions を使うメリットを解説します!",
},
];
module.exports = {
DUMMY_PASSWORD,
USER_DATA,
POST_DATA,
};
まとめ
本記事では、Prisma のプロジェクトへの追加方法、スキーマ定義や使い方について簡単に説明しました。
Prisma を使うことで、スキーマ定義 → テーブル作成 → クライアント生成 → ダミーデータ投入までが簡潔に行えますので、開発効率を向上させることができます。
最後に、Prisma モデルの定義でよく使うパラメータをまとめておきます。
よく使う Prisma の属性
属性名(アノテーション) | 用途・意味 |
---|---|
@id |
主キー(Primary Key)を指定する。1 つのモデルに 1 つのみ設定可能。 |
@default(...) |
フィールドのデフォルト値を設定。now() 、uuid() 、cuid() などが使用可能。 |
@unique |
一意制約(UNIQUE)を設定。同じ値の重複登録を禁止する。 |
@updatedAt |
レコード更新時にこの日時フィールドを自動更新。DateTime 型と併用。 |
@relation(...) |
他のモデルとのリレーションを定義。外部キーの指定やリレーションの挙動を制御する。 |
よく使う @default
の引数
引数名 | 説明 |
---|---|
now() |
現在時刻(DateTime 型)を設定 |
uuid() |
UUID(RFC4122)形式の文字列を生成 |
cuid() |
一意な文字列 ID(短く可読性が高い)を生成 |
リテラル値 | 例: true , "text" , 0 , [] など |
@relation
の詳細オプション
オプション名 | 説明 |
---|---|
fields: [...] |
外部キーとなるローカルのフィールド名を指定。 |
references: [...] |
外部のテーブルのどのカラムを参照するかを指定。 |
onDelete |
外部キーの対象が削除されたときの動作。例: Cascade , SetNull , Restrict
|
onUpdate |
外部キーの対象が更新されたときの動作。通常は Restrict や Cascade
|
name: "..." |
リレーション名を明示的に設定。省略可能。 |