Claude Code × データベース開発完全ガイド|Prisma・Drizzle ORMとの連携・CLAUDE.mdテンプレート・MCPサーバー活用まで

Claude Code × データベース開発完全ガイド|Prisma・Drizzle ORMとの連携・CLAUDE.mdテンプレート・MCPサーバー活用まで AI開発

Claude Codeは「コードを書く」ツールとして知られていますが、データベース開発との相性が特に良いです。スキーマ設計の議論、マイグレーションの安全性チェック、N+1問題の自動検出、ClaudeのMCPサーバー経由での直接DB操作まで、DB開発のすべてのフェーズでAIに任せられる作業が増えています。

この記事では、TypeScriptプロジェクトで最もよく使われる2つのORM——PrismaとDrizzle——を対象に、Claude Codeを使ったデータベース開発の実践的なワークフローを解説します。CLAUDE.mdへのコピペ即使えるDB設定テンプレートも用意しました。

Prisma v7(2025年11月リリース)・Drizzle v1 beta(2025年2月)の最新情報をもとに書いています。TypeScript記事でそれぞれの使い方を解説したPrismaのTypeScript完全ガイドDrizzle ORMのTypeScript完全ガイドもあわせてご覧ください。
スポンサーリンク

Claude CodeとDB開発の相性が良い理由

テキストエディタで書くコードと違い、DBスキーマには「全体像」が常に必要です。新しいテーブルを追加するとき、既存のリレーションへの影響、インデックスの是非、マイグレーションの安全性を一気に考えなければなりません。これはまさにClaude Codeが得意とする「文脈を踏まえた総合的な判断」が求められる領域です。

  • スキーマ全体を一度に把握できる: .prismaファイルやdrizzle/schema.tsをコンテキストに読み込めば、全テーブルの構造を理解した上で提案できる
  • 破壊的変更を自動検出できる: マイグレーションSQLを読んでテーブルロックやデータ損失リスクを事前に警告できる
  • N+1問題をコードレビューで自動検出できる: ループ内のDB呼び出しパターンを発見し、最適化済みのコードを提案できる
  • MCPサーバー経由でDBを直接操作できる(Prismaのみ): Claude Codeからマイグレーション実行やデータ確認が可能

Prisma vs Drizzle ── Claude Codeと使う場合の選択基準

どちらのORMもClaude Codeと組み合わせて使えますが、特性が異なります。

観点 Prisma v7 Drizzle v1
バンドルサイズ 1.6MB(v7でRust→TS再実装により90%削減) 7.4KB(約228分の1)
型チェック速度 高速(型インスタンス数: 約427) やや遅い(型インスタンス数: 約59,000)
スキーマ記述 専用言語PSL(.prismaファイル) TypeScript
SQLとの近さ 高抽象(contains/startsWith SQL直結(like/ilike
MCPサーバー 公式MCPあり(v6.6.0〜) なし
Claude Codeとの相性 自然言語での設計指示がしやすい、MCP経由で直接操作可能 SQLに近い記法で生成コードが予測しやすい
推奨シーン チーム開発・複雑なリレーション・管理ツール重視 エッジ/サーバーレス・パフォーマンス重視・SQL習熟者
MCPサーバーを使ってClaude Codeにデータベースを直接操作させたい場合は、現時点ではPrismaが唯一の選択肢です。

CLAUDE.mdへのDB設定テンプレート

Claude CodeにDB開発を依頼する前に、プロジェクトのCLAUDE.mdへDB設計の規約を記述しておくことが重要です。一度設定すれば、Claude Codeが毎回同じ規約に従ったコードを生成するようになります。

Prisma版 CLAUDE.mdテンプレート

CLAUDE.md(Prisma版)
## Database(Prisma + PostgreSQL)

### 命名規則
- テーブル名: PascalCase(Prismaの規約) → DBはsnake_caseに自動マッピング
- カラム名: camelCase(Prisma)→ DBはsnake_case(@@map/@mapで明示)
- モデル名をそのままAPIレスポンスに使わない(DTOを経由する)

### クエリルール
- ループ内のDB呼び出し禁止(N+1問題)
- 関連データはinclude/selectで一括取得する
- リスト取得は必ずtake(上限)を設定する
- SELECT *相当(全フィールド取得)は禁止。必要フィールドをselectで指定
- _countで集計はDBレイヤーで行う

### マイグレーションルール
- 開発環境: npx prisma migrate dev --name <説明的な名前>
- 本番環境: npx prisma migrate deploy(CI/CDから実行)
- マイグレーションファイルは手動編集禁止
- スキーマ変更後は必ず npx prisma generate を実行
- prisma migrate reset は本番DB絶対禁止
- カラム削除は2デプロイで段階的実施:
  1. コードから参照削除 → デプロイ
  2. 次スプリントでカラム削除マイグレーション作成

### 安全ルール
- 大テーブルへのインデックス追加はCONCURRENTLYオプション検討
- NOT NULL追加はDEFAULT値を同時設定するか段階的実施
- prisma db pushは本番環境で使用しない

Drizzle版 CLAUDE.mdテンプレート

CLAUDE.md(Drizzle版)
## Database(Drizzle ORM + PostgreSQL)

### 命名規則
- テーブル名: 複数形・snake_case(users, blog_posts, post_tags)
- カラム名: DBはsnake_case、TypeScriptはcamelCase(自動マッピング)
- インデックス名: table_column_idx形式(例: users_email_idx)

### スキーマ規約
- IDカラム: serialではなくgeneratedAlwaysAsIdentity()を使う(2025年標準)
- タイムスタンプ: timestamptz({ precision: 3 }) で統一
- 外部キーには必ずインデックスを張る
- JSONカラム: jsonb().$type<型名>() で型付きにする

### クエリルール
- ループ内のDB呼び出し禁止(N+1問題)
- 関連データはdb.query.xxx.findMany()の関連クエリAPIを使う
- 必要カラムのみcolumnsプロパティで指定する
- 頻繁なクエリはprepare()でPrepared Statementにする

### マイグレーションルール
- 開発: npx drizzle-kit push(スキーマを直接プッシュ)
- 本番: npx drizzle-kit generate → npx drizzle-kit migrate
- 生成されたSQLは適用前に必ず確認する
CLAUDE.mdの詳しい書き方についてはCLAUDE.md完全ガイドをご覧ください。

PrismaでのClaude Code実践ワークフロー

スキーマ設計をClaude Codeに依頼する

スキーマ設計の依頼では、システム概要・エンティティ・非機能要件を一度に伝えるのがポイントです。

スキーマ設計依頼プロンプト
schema.prismaを新規作成してください。

## システム概要
ブログサービス(月間10万PV、検索クエリが多い)

## エンティティ
- User: メール認証、ソフトデリート必要
- Post: 下書き/公開/アーカイブのステータス管理
- Tag: 多対多リレーション

## 設計基準
1. 全外部キーにインデックスを張る
2. よく使うフィルタ(status, publishedAt)に複合インデックスを追加
3. N+1が起きないリレーション設計
4. 設計理由をコメントで記載する

作成後にN+1リスクがある箇所を自己レビューしてください。
生成されるスキーマの例(schema.prisma)
// User: ソフトデリート対応(deletedAtがある場合は削除済み)
model User {
  id        String   @id @default(uuid())
  email     String   @unique
  name      String
  posts     Post[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  deletedAt DateTime? // ソフトデリート

  @@map("users")
}

model Post {
  id          String     @id @default(uuid())
  title       String
  content     String     @db.Text
  status      PostStatus @default(DRAFT)
  authorId    String
  author      User       @relation(fields: [authorId], references: [id])
  tags        PostTag[]
  publishedAt DateTime?
  createdAt   DateTime   @default(now())
  updatedAt   DateTime   @updatedAt

  // 複合インデックス: statusとpublishedAtでよく絞り込むため
  @@index([status, publishedAt])
  // N+1対策: authorIdへのインデックス(外部キー必須)
  @@index([authorId])
  @@map("posts")
}

enum PostStatus {
  DRAFT
  PUBLISHED
  ARCHIVED
}

マイグレーションの安全性チェックを依頼する

マイグレーションを実行する前に、Claude Codeに生成されたSQLを確認させる習慣をつけましょう。

マイグレーション安全チェックプロンプト
npx prisma migrate devを実行し、生成されたSQLファイルを読んで
以下を確認してください:
1. テーブルロックが発生する操作がないか
2. データ損失のリスクがある変更がないか(DROP COLUMN等)
3. 大テーブルへのインデックス追加がないか(CONCURRENTLYが必要)
4. 問題があれば migrate dev を中止し、代替手順を提案してください
破壊的変更の安全な進め方(プロンプト例)
postsテーブルのbodyカラムをcontentにリネームし、
NOT NULL制約を追加したい(現在データ5万件)。

ダウンタイムなしで安全に移行する手順を提案してください:
- 段階的な移行ステップ
- 各ステップで実行するPrismaコマンド
- ロールバック手順
- リスク説明
カラムのリネームや削除は直接マイグレーションを生成するのではなく、「コードから参照を削除→デプロイ→別のマイグレーションでカラム削除」という2ステップが安全です。Claude Codeに相談すると、このような段階的手順を提案してくれます。

CRUD自動生成を依頼する

リポジトリ層の自動生成プロンプト
schema.prismaのPostモデルに対して以下を生成してください:

1. src/repositories/post.repository.ts
   - findById(authorとタグを含む)
   - findMany(ページング付き、ステータスフィルター)
   - create(ドラフト作成)
   - publish(公開 + publishedAt設定)
   - softDelete(deletedAtを設定)

実装規約:
- 全フィールド取得しない(必要なselectを明示)
- 型はPrismaが生成した型を使う(独自型は作らない)
- エラーは上位層に投げる(try-catchしない)
生成されるコードの例
import { prisma } from "@/lib/prisma";
import { Prisma } from "@prisma/client";

// 取得カラムを明示(SELECT *は使わない)
const postSelectFields = {
  id: true,
  title: true,
  content: true,
  status: true,
  publishedAt: true,
  createdAt: true,
  author: { select: { id: true, name: true } },
  tags: { select: { tag: { select: { id: true, name: true } } } },
} satisfies Prisma.PostSelect;

export const postRepository = {
  async findById(id: string) {
    return prisma.post.findUnique({
      where: { id, deletedAt: null },
      select: postSelectFields,
    });
  },

  async findMany(params: { page: number; limit: number; status?: string }) {
    const { page, limit, status } = params;
    const [posts, total] = await prisma.$transaction([
      prisma.post.findMany({
        where: { deletedAt: null, ...(status ? { status } : {}) },
        select: postSelectFields,
        take: limit,
        skip: (page - 1) * limit,
        orderBy: { createdAt: "desc" },
      }),
      prisma.post.count({ where: { deletedAt: null } }),
    ]);
    return { posts, total };
  },
};

Prisma MCPサーバー ── Claude Codeからデータベースを直接操作する

Prisma v6.6.0(2025年)から提供されているMCPサーバーを使うと、Claude CodeからDBの状態確認やマイグレーション操作が直接できるようになります。

Prisma MCPサーバーの追加
# ローカル開発用(prisma migrate devなどを操作)
claude mcp add prisma-local -- npx -y prisma mcp

# Prisma Postgresクラウド用(リモート管理)
claude mcp add --transport http prisma-remote https://mcp.prisma.io/mcp

MCPサーバーを追加すると、Claude Codeが以下の操作を直接実行できるようになります:

  • マイグレーション状態の確認(migrate-status
  • 開発用マイグレーションの実行(migrate-dev
  • Prisma Studioの起動
  • スキーマのイントロスペクション(既存DBからスキーマ生成)
  • クラウド版ではSQL実行・バックアップ作成/復元も可能
MCPを使った会話例
# Claude Codeのターミナルで
> マイグレーションの適用状況を確認して

> 現在の全テーブルのレコード数を確認して

> postsテーブルに先週追加されたレコードを10件見せて

# Claude Codeが prisma mcp のツールを呼び出して直接DBを確認する
Prisma MCPサーバーにはセーフガードが組み込まれており、migrate resetなどの破壊的操作はAIエージェントから自動実行できません。ユーザーの明示的な承認が必要な設計になっています。

MCPサーバーの詳しい設定方法はClaude Code MCP完全ガイドで解説しています。

DrizzleでのClaude Code実践ワークフロー

スキーマ定義を依頼する

DrizzleはTypeScriptでスキーマを書くため、Claude Codeへの指示もTypeScriptの文脈で自然に伝えられます。

Drizzleスキーマ生成プロンプト
以下の仕様でDrizzle ORMのスキーマを定義してください。

## 使用DB: PostgreSQL
## テーブル: users, posts, tags(多対多)

## 必ず従う規約
- テーブル名: 複数形・snake_case(users, blog_posts)
- IDカラム: generatedAlwaysAsIdentity()を使う(serialは使わない)
- タイムスタンプ: timestamptz({ precision: 3 }) で統一
- 外部キーには必ずインデックスを張る
- JSONカラム: jsonb().$type<型名>() で型付きにする
- drizzle-zodでcreateInsertSchema/createSelectSchemaも生成する
生成されるスキーマの例(drizzle/schema.ts)
import { pgTable, text, varchar, timestamp, integer, pgEnum, index, uniqueIndex } from "drizzle-orm/pg-core";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { relations } from "drizzle-orm";

export const postStatusEnum = pgEnum("post_status", ["draft", "published", "archived"]);

export const users = pgTable("users", {
  id: integer("id").generatedAlwaysAsIdentity().primaryKey(),
  email: varchar("email", { length: 255 }).notNull().unique(),
  name: varchar("name", { length: 100 }).notNull(),
  createdAt: timestamp("created_at", { precision: 3, withTimezone: true }).defaultNow().notNull(),
  deletedAt: timestamp("deleted_at", { precision: 3, withTimezone: true }),
}, (t) => [
  uniqueIndex("users_email_idx").on(t.email),
]);

export const posts = pgTable("posts", {
  id: integer("id").generatedAlwaysAsIdentity().primaryKey(),
  title: varchar("title", { length: 500 }).notNull(),
  content: text("content").notNull(),
  status: postStatusEnum("status").default("draft").notNull(),
  authorId: integer("author_id").notNull().references(() => users.id),
  publishedAt: timestamp("published_at", { precision: 3, withTimezone: true }),
  createdAt: timestamp("created_at", { precision: 3, withTimezone: true }).defaultNow().notNull(),
}, (t) => [
  index("posts_author_id_idx").on(t.authorId),  // 外部キーのインデックス
  index("posts_status_published_at_idx").on(t.status, t.publishedAt), // 複合インデックス
]);

// Drizzle-Zod統合
export const insertUserSchema = createInsertSchema(users);
export const selectUserSchema = createSelectSchema(users);

Relational APIで関連データを取得する(Drizzle v1)

Drizzle v1のRelational API v2では、PrismaのincludeライクなAPIでN+1なしに関連データを取得できます。

Relational APIの使い方(Claude Codeへの指示後)
// drizzle/relations.ts
import { relations } from "drizzle-orm";
import { posts, users, tags, postTags } from "./schema";

export const usersRelations = relations(users, ({ many }) => ({
  posts: many(posts),
}));

export const postsRelations = relations(posts, ({ one, many }) => ({
  author: one(users, { fields: [posts.authorId], references: [users.id] }),
  postTags: many(postTags),
}));

// 使用時: authorとtagsを1クエリで取得(N+1なし)
const result = await db.query.posts.findMany({
  where: (posts, { eq }) => eq(posts.status, "published"),
  with: {
    author: { columns: { id: true, name: true } },
    postTags: { with: { tag: true } },
  },
  limit: 20,
  orderBy: (posts, { desc }) => [desc(posts.publishedAt)],
});

drizzle-kitのコマンド一覧

コマンド 用途 環境
drizzle-kit push スキーマを直接DBにプッシュ(マイグレーションファイルなし) 開発
drizzle-kit generate スキーマ変更からSQLマイグレーションファイルを生成 両方
drizzle-kit migrate 生成済みマイグレーションをDBに適用 本番
drizzle-kit pull 既存DBをイントロスペクトしてスキーマ生成 開発
drizzle-kit studio GUIでDB閲覧・操作(Drizzle Studio) 開発
drizzle-kit check マイグレーション競合チェック CI/CD

Claude CodeにN+1問題を自動検出させる

N+1問題はPRレビューで見落とされやすい問題です。Claude Codeに定期的にコードレビューを依頼するワークフローを作りましょう。

N+1検出レビュープロンプト
以下のコードをレビューしてN+1問題とスロークエリを検出してください:

[コードをペースト、または /add でファイルを追加]

改善点ごとに:
1. 問題の説明(どのループで何回クエリが発生するか)
2. 改善後のコード
3. 改善前後の想定クエリ数比較

を示してください。
N+1が発生するNG例と修正例
// NG: ループ内でDB呼び出し(投稿数が100件なら101クエリ発生)
const posts = await prisma.post.findMany({ take: 100 });
for (const post of posts) {
  const author = await prisma.user.findUnique({  // ← ここでN+1!
    where: { id: post.authorId }
  });
  console.log(post.title, author?.name);
}

// OK: includeで1クエリに(Claude Codeが提案する修正)
const posts = await prisma.post.findMany({
  take: 100,
  include: {
    author: { select: { id: true, name: true } }
  }
});
for (const post of posts) {
  console.log(post.title, post.author.name);  // ← クエリ発生なし
}
CLAUDE.mdに「ループ内のDB呼び出し禁止」と明記しておくと、Claude Codeが自動的にN+1を避けたコードを生成するようになります。

CI/CDへのマイグレーションチェック組み込み

PRのたびにClaude Codeがマイグレーションを自動チェックするワークフローを構築できます。

GitHub Actions: マイグレーション自動チェック(.github/workflows/db-check.yml)
name: DB Migration Check

on:
  pull_request:
    paths:
      - "prisma/migrations/**"
      - "drizzle/**"
      - "schema.prisma"

jobs:
  migration-review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Check changed migration files
        run: |
          CHANGED=$(git diff --name-only origin/main...HEAD -- prisma/migrations/ drizzle/)
          if [ -z "$CHANGED" ]; then
            echo "No migration changes detected"
            exit 0
          fi

          echo "Changed migration files:"
          echo "$CHANGED"

          # Claudeにマイグレーションの安全性をチェックさせる
          for f in $CHANGED; do
            if [[ "$f" == *.sql ]]; then
              cat "$f" | claude --bare -p \
                "このマイグレーションSQLに破壊的変更(DROP/TRUNCATE/テーブルロック)があれば警告して" \
                --output-format stream-json | jq -r ".text"
            fi
          done
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          DISABLE_AUTOUPDATER: 1

Claude Codeへのよくある指示テンプレート集

DB開発でよく使う指示のテンプレートをまとめました。コピペして使ってください。

インデックス最適化の依頼

インデックス最適化プロンプト
以下のクエリが遅い(スローログに出ている)。
EXPLAINの出力と現在のスキーマを見て最適なインデックスを提案してください。

## スローログのクエリ
[クエリをペースト]

## EXPLAINの出力
[EXPLAIN ANALYZEの結果をペースト]

## 現在のインデックス
[関連テーブルのスキーマをペースト]

追加するインデックス、削除できるインデックス、
複合インデックスへの統合ができる箇所を具体的に提案してください。

既存DBからのスキーマ生成

既存DBからスキーマを生成するプロンプト
# Prismaの場合
> npx prisma db pull を実行して既存のDBからスキーマを生成してください。
> 生成後、以下を改善してください:
> 1. 適切なリレーション定義を追加
> 2. 欠けているインデックスを追加
> 3. 命名規則に合わないカラムをmapで修正

# Drizzleの場合
> npx drizzle-kit pull を実行して既存DBからスキーマを生成してください。
> 生成後、relationsファイルも作成してください。

テストデータ(シード)の生成

シードデータ生成プロンプト
prisma/seed.tsを作成してください。

要件:
- User: 5件(管理者1・一般4)
- Post: 各ユーザーに3件(PUBLISHED/DRAFT混在)
- Tag: 10件、各投稿に2〜4件紐づける
- パスワードはbcryptでハッシュ化
- 開発用なのでリセット・再実行可能な設計

実行コマンド: npx ts-node prisma/seed.ts

よくある質問

QPrismaとDrizzleのどちらを選べばよいですか?
Aチーム規模が大きい・複雑なリレーションが多い・DB管理UIが欲しい場合はPrismaが適しています。サーバーレス環境・エッジ環境・パフォーマンスを最優先する場合はDrizzleが有利です。Claude Code連携の観点では、MCP経由でDBを直接操作したい場合はPrisma一択です。
QPrisma v7は以前のバージョンからの移行が大変ですか?
A主な変更点はジェネレータ名(prisma-client-jsprisma-client)とBytesフィールドの型(BufferUint8Array)です。schema.prismaの1行を変えてコードを検索・置換する程度で、ほとんどのプロジェクトは1〜2時間で移行できます。バンドルサイズが大幅に小さくなるため移行の価値は高いです。
QPrisma MCPサーバーは本番DBに接続しても安全ですか?
APrismaの公式MCPサーバーにはmigrate resetなどの破壊的操作に対するセーフガードが組み込まれています。ただし、本番DBへの接続は最小権限の原則に従い、SELECT専用のユーザーを使うことを推奨します。
QClaude CodeにN+1を検出させるには何をコンテキストに入れればよいですか?
Aリポジトリ層のファイル(/add src/repositories)とスキーマファイル(/add schema.prisma または /add drizzle/schema.ts)をコンテキストに追加してから依頼するのが効果的です。CLAUDE.mdに「N+1禁止」ルールを記述しておくと、コード生成時に自動的に回避されます。
Q既存のRawクエリをPrisma/Drizzleに移行するにはどう指示すればよいですか?
A/addで既存のRawクエリファイルを追加し、「このRawクエリをPrismaのTyped SQL APIを使って書き直してください」と依頼します。Prismaのv6以降はTyped SQL(型安全なrawクエリ)が使えるため、パフォーマンスが重要な部分はRawクエリを保ちながら型安全性を確保できます。

まとめ

Claude Codeとデータベース開発の組み合わせは、特に以下の場面で効果を発揮します。

  • スキーマ設計の壁打ち: 要件を伝えれば、インデックス設計・N+1対策・マイグレーション安全性を考慮したスキーマを提案してもらえる
  • CLAUDE.mdへのDB規約の一元管理: 命名規則・クエリルール・マイグレーション手順を書いておけば、生成されるコードが常に規約に従う
  • マイグレーションの安全性チェック: 本番適用前に生成SQLを読んで破壊的変更を検出できる
  • Prisma MCPサーバー連携: Claude Codeからマイグレーション状態の確認・スキーマ生成が直接できる
  • N+1問題の自動検出: PRレビュー時にDB呼び出しパターンを解析して最適化を提案できる

DB開発はミスが本番データに直結するため、慎重に進める必要があります。Claude Codeを「第二のレビュアー」として使うことで、変更前に問題を検出できるようになります。

Prismaの基本的な使い方はTypeScript × Prisma完全ガイド、Drizzleの使い方はTypeScript × Drizzle ORM完全ガイドで詳しく解説しています。また、Claude Code全体の使い方はClaude Code入門ガイドをご覧ください。