D1+Prismaの本番マイグレーション:コマンド順序と4つの失敗パターン

D1+Prismaの本番マイグレーション:コマンド順序と4つの失敗パターン

※本記事にはプロモーション(広告・アフィリエイトリンク)を含みます。

Cloudflare D1 に Prisma を乗せた構成でスキーマを変更するとき、コマンドの実行順序がひとつ狂うだけで Worker がエラーを返し続ける状態になる。prisma migrate dev が D1 で使えない理由、本番反映の正しい順序、順序ミスが引き起こす具体的な壊れ方まで、手順を整理した。

なぜ prisma migrate dev は D1 で使えないのか

Prisma の通常フロー(PostgreSQL・MySQL・ローカル SQLite ファイル)では、prisma migrate dev がマイグレーションファイルの生成・適用・クライアント再生成を一括で処理する。しかし Cloudflare D1 は Cloudflare のランタイムが管理する SQLite であり、Prisma の Migration Engine が TCP/IP で直接接続することができない。

D1 へのマイグレーション適用は Wrangler 経由でしか行えないため、prisma migrate dev や prisma migrate deploy はそのままでは動かない。実行すると Migration Engine が接続先を見つけられずエラーになる。

執筆時点(2026年9月)では、Prisma は @prisma/adapter-d1 を通じた D1 サポートを提供している。Prisma の役割は「差分 SQL の生成」と「クライアント型定義の更新」に限られ、SQL の実際の適用は Wrangler の d1 migrations apply コマンドが担う設計になっている。この分担を理解していないと、コマンドの順序を誤りやすい。

正しいコマンド順序

schema.prisma を変更済みの状態から始める

# ステップ1:差分 SQL を生成する
npx prisma migrate diff \
  --from-local-d1 \
  --to-schema-datamodel prisma/schema.prisma \
  --script \
  --output migrations/0002_add_stock_reserved.sql

--from-local-d1 は Wrangler がローカルに保持している D1 のスキーマを「現在地」として参照する。--to-schema-datamodel は prisma/schema.prisma が定義する「目指す状態」。このコマンドは SQL ファイルを生成するだけで DB には触れない。生成された SQL を目視確認してから次に進む。

# ステップ2:ローカル D1 で動作確認
wrangler d1 migrations apply DB_NAME --local

DB_NAME は wrangler.toml 内の [[d1_databases]] に書いた database_name の値。--local を付けることでローカルの開発用 DB にのみ適用される。

# ステップ3:開発サーバーで動作確認
wrangler dev
# ステップ4:本番 D1 にマイグレーションを適用する(ここが核心)
wrangler d1 migrations apply DB_NAME --remote

このコマンドが完了してはじめて本番 DB のスキーマが変わる。アプリコードのデプロイはこのステップの後。

# ステップ5:Prisma クライアントを再生成する
npx prisma generate

schema.prisma が変わったので型定義を更新する。これをしないと TypeScript の型が旧スキーマのままになり、新カラムへのアクセスがビルドエラーとして現れる。

# ステップ6:Worker または Next.js をデプロイ
wrangler deploy

手順の要約

ステップ コマンド 本番 DB 本番コード
1 prisma migrate diff ... --script 変更なし 変更なし
2 wrangler d1 migrations apply ... --local 変更なし 変更なし
3 wrangler dev で確認 変更なし 変更なし
4 wrangler d1 migrations apply ... --remote 変更 変更なし
5 prisma generate 変更なし 型更新のみ
6 wrangler deploy 変更なし 変更

4→6 の順番を守る理由は、「DB のみ変更された状態」では旧コードが旧スキーマ対応のまま動き続けるため(カラム追加の場合)壊れないから。逆に 6→4 の順にすると、新コードが旧スキーマの DB に当たって即座にエラーになる。

順序を間違えたときの失敗パターン

パターン1:コードが新、DB が旧(デプロイを先にした)

新しいカラムを参照するコードを先にデプロイし、本番 DB はまだ旧スキーマのままにした場合。Worker は存在しないカラムに対して SELECT や INSERT を発行し、SQLite が SQLITE_ERROR: no such column を返す。読み取りなら 500 エラー、書き込みならトランザクション失敗でデータが保存されない。

回復手順: ステップ4(wrangler d1 migrations apply ... --remote)を急いで実行する。カラム追加であれば既存データは残る。カラム削除・型変更を伴う場合はデータ欠損のリスクがあるため、Wrangler の d1 export コマンドで先にバックアップを取ること(最新のフラグは公式ドキュメントを参照)。

パターン2:--remote を付け忘れた(ローカルにしか適用していない)

# 危険な例(--remote も --local も明示していない)
wrangler d1 migrations apply DB_NAME

Wrangler のバージョンや設定によってデフォルト挙動が変わる可能性があるため(環境によって異なります)、--remote か --local を必ず明示する。適用後は以下で本番 DB の構造を確認する。

wrangler d1 execute DB_NAME --remote --command "PRAGMA table_info(products);"

カラムが増えていなければ本番 DB にはまだ当たっていない。

パターン3:prisma generate を忘れた

DB への適用もデプロイも済んだのに prisma generate を忘れると、TypeScript の型定義ファイルが旧スキーマのままになる。次の開発で新カラムにアクセスしようとした際に型エラーが出てビルドが通らなくなる。schema.prisma を変更したら prisma generate をセットにする習慣をつけること。

パターン4:マイグレーションファイルの連番が衝突した

複数ブランチで並行開発すると、同じ連番(例:0003_)が付いたファイルが複数できることがある。Wrangler はファイル名のアルファベット順で適用済みを管理するため、同じプレフィックスが重複すると履歴が壊れる。タイムスタンプをプレフィックスにする方法が現実的な対策。

migrations/
  20260915120000_add_stock_reserved.sql
  20260918093000_add_category_index.sql

prisma migrate diff の --output にタイムスタンプを含めて呼び出すシェルスクリプトを用意しておくと手動ミスを減らせる。

ロールバック手順

D1 は執筆時点で自動ロールバック機能を持たないため、スキーマを元に戻す SQL を手動で用意して適用する。

# カラム追加のロールバック例
wrangler d1 execute DB_NAME --remote --command "ALTER TABLE products DROP COLUMN stock_reserved;"

SQLite 3.35 以降でカラム削除がサポートされているが、D1 が実際に使う SQLite バージョンは Cloudflare のランタイムに依存するため、公式ドキュメントで確認してから実行すること。

ロールバック用 SQL をあらかじめ .down.sql ファイルとして用意しておくのが堅実な保険になる。

migrations/
  0002_add_stock_reserved.sql        ← wrangler が適用
  0002_add_stock_reserved.down.sql   ← ロールバック用(手動実行)

.down.sql は Wrangler が自動で使うわけではなく、手動実行のための参照ファイル。

まとめ

Cloudflare D1 + Prisma のマイグレーションは「差分 SQL 生成 → ローカル確認 → 本番 DB 適用 → prisma generate → デプロイ」の順が原則。DB とコードの更新を逆にするとサービスが止まる。

次のアクションとして、今使っている schema.prisma に対して prisma migrate diff --from-local-d1 --to-schema-datamodel prisma/schema.prisma --script を実行し、出力が空(差分ゼロ)になるかを確認してほしい。差分が出るなら、それが今すぐ対処すべき未適用のスキーマ変更だ。

よくある質問

prisma migrate dev を D1 で実行するとエラーになります。どうすれば直りますか?

D1 は Prisma Migration Engine が直接接続できないため `prisma migrate dev` は使えません。`prisma migrate diff --from-local-d1` で差分 SQL を生成し、`wrangler d1 migrations apply --remote` で本番に適用するフローに切り替えてください。

wrangler d1 migrations apply を実行したのに本番 DB に変更が反映されていません

コマンドに --remote を付け忘れている可能性があります。`wrangler d1 execute DB_NAME --remote --command` でテーブル構造を確認し、カラムが増えていなければ --remote を明示して migrations apply を再実行してください。

D1 マイグレーションのロールバックはどうやるのですか?

D1 に自動ロールバック機能はありません。`wrangler d1 execute DB_NAME --remote --command` で元に戻す SQL(DROP COLUMN など)を手動で適用します。事前に .down.sql ファイルを用意しておくのが確実な備えです。