0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Next.js プロジェクトに Prisma を導入する方法と基本操作まとめ

Last updated at Posted at 2025-05-03

はじめに

本記事では、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 を使用する場合、以下の通り設定します。

prisma/schema.prisma
datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}
.env
DATABASE_URL="file:./dev.db"

Prisma モデルの設定

prisma/schema.prisma に Prisma モデルを記述します。
それぞれの定義内容を順番に見ていきます。

Prisma モデル: User

1. スキーマ定義
prisma/schema.prisma
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. スキーマ定義
prisma/schema.prisma
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 は、
モデル Userid を参照しており、
もしその User が削除されたら、紐づく Post も 自動的に削除される(Cascade

というリレーションです。

オプション 説明
fields: [authorId] 現在のモデル(この場合 Post)で外部キーとして使うフィールドを指定します。このフィールドが、他のモデルの主キー等と一致する値を保持します。
references: [id] リレーション先のモデル(この場合 User)の、対応するフィールド(通常は主キー)を指定します。
onDelete: Cascade リレーション先(この場合 User)のデータが削除された時の動作を定義します。この場合は「連動して Post も削除される」という設定です。

この定義により、以下のことが保証されます:

  • PostauthorId は、必ず存在する 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 のクライアントを設定します。

prisma.ts
// 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 に出力するよう指定します。

schema.prisma
generator client {
  provider = "prisma-client-js"
  output   = "../src/generated/prisma"
}

3. シードスクリプト(ダミーデータ挿入)

ダミーデータを挿入する seed.cjs スクリプトです。

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 スクリプトを追加

package.json
  "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 の内容を取得し、画面に表示します。

@/app/blog/page.tsx
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 にアクセスすると、作成したダミーデータが画面に表示されていることが確認できます。

image.png

(補足)スタイリングとダミーデータの中身

この記事の本題は Prisma の使い方ですが、画面表示やシード作成に使った CSS クラスやダミーデータの中身についても、参考として簡単に紹介しておきます。

Tailwind CSS のカスタムクラス定義

Tailwind CSS のユーティリティクラスを同じ要素に繰り返し適用している場合、共通化の方法がいくつか用意されています。
今回は globals.css@apply ディレクティブを使ってカスタムクラスを定義し、<th> タグと <td> タグに設定しています。

globals.css
@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;
}
ダミーデータの中身

シードスクリプトで使っているダミーデータです。

prisma/data/dummyData.js
// ユーザーパスワード
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 外部キーの対象が更新されたときの動作。通常は RestrictCascade
name: "..." リレーション名を明示的に設定。省略可能。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?