d1-migration について
Drizzle ORM と Cloudflare D1 を使う開発者向けのマイグレーション手順です。SQL の確認、ローカルとリモートへの適用、検証や復旧に加え、一括挿入の分割と命名規則も扱います。
主な機能
- 01マイグレーション SQL の生成と確認
- 02ローカル・リモートへの適用
- 03スキーマと適用記録の検証
- 04停止したマイグレーションの診断と修復
- 05大量の挿入処理の分割
活用シーン
- 01生成 SQL にテーブル再作成がないか確認
- 02ローカルとリモートの D1 スキーマを同期
- 03重複カラムや未記録の移行問題を解消
- 04一括挿入時のパラメーター制限を回避
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jezweb/ claude-skills --skill d1-migrationインストール後、Claude Code で/d1-migrationを入力して読み込まれたか確認します。
詳細
D1 マイグレーションのワークフロー
Drizzle ORM を使用した Cloudflare D1 データベースのマイグレーションを案内するワークフローです。
標準的なマイグレーションの流れ
1. マイグレーションを生成する
pnpm db:generate
drizzle/(または設定したマイグレーションディレクトリ)に新しい .sql ファイルが作成されます。
2. SQL を確認する(重要)
適用する前に、必ず生成された SQL を読んでください。 Drizzle は、単純なスキーマ変更でも破壊的なマイグレーションを生成することがあります。
要注意:テーブルの再作成
このパターンが見られる場合、マイグレーションは失敗する可能性が高いです。
CREATE TABLE `my_table_new` (...);
INSERT INTO `my_table_new` SELECT ..., `new_column`, ... FROM `my_table`;
-- ^^^ This column doesn't exist in old table!
DROP TABLE `my_table`;
ALTER TABLE `my_table_new` RENAME TO `my_table`;
原因:Drizzle スキーマでカラムの default 値を変更すると、テーブル全体の再作成が発生します。INSERT SELECT が、古いテーブルに存在しない新しいカラムを参照します。
修正方法:新しいカラムを追加するだけで(既存カラムの型や制約を変更しない場合)あれば、次のようにシンプルにします。
ALTER TABLE `my_table` ADD COLUMN `new_column` TEXT DEFAULT 'value';
適用する前に .sql ファイルを直接編集してください。
3. ローカルに適用する
pnpm db:migrate:local
# or: npx wrangler d1 migrations apply DB_NAME --local
4. リモートに適用する
pnpm db:migrate:remote
# or: npx wrangler d1 migrations apply DB_NAME --remote
テストする前に、必ずローカルとリモートの両方に適用してください。 ローカルのみにマイグレーションを適用すると、「ローカルでは動くが、本番環境では壊れる」という分かりにくい問題が発生します。
5. 検証する
# Check local
npx wrangler d1 execute DB_NAME --local --command "PRAGMA table_info(my_table)"
# Check remote
npx wrangler d1 execute DB_NAME --remote --command "PRAGMA table_info(my_table)"
停滞したマイグレーションの修正
マイグレーションが一部だけ適用された場合(例:カラムは追加されたが、マイグレーションの記録はされていない)、wrangler は再実行を試みますが、重複カラムのため失敗します。
症状:完了しているはずのマイグレーションで pnpm db:migrate がエラーになります。PRAGMA table_info ではカラムが存在することが確認できます。
診断
# 1. Verify the column/table exists
npx wrangler d1 execute DB_NAME --remote \
--command "PRAGMA table_info(my_table)"
# 2. Check what migrations are recorded
npx wrangler d1 execute DB_NAME --remote \
--command "SELECT * FROM d1_migrations ORDER BY id"
修正
# 3. Manually record the stuck migration
npx wrangler d1 execute DB_NAME --remote \
--command "INSERT INTO d1_migrations (name, applied_at) VALUES ('0013_my_migration.sql', datetime('now'))"
# 4. Run remaining migrations normally
pnpm db:migrate
予防
CREATE TABLE IF NOT EXISTS— 再実行しても安全ですALTER TABLE ADD COLUMN— SQLite にはIF NOT EXISTSを指定する形式がありません。先にカラムの存在を確認するか、アプリケーションコードで try/catch を使用してください- 適用する前に、必ず生成された SQL を確認してください(上記のステップ 2)
一括 INSERT の分割
D1 のパラメーター数の上限により、大量の複数行 INSERT がサイレントに失敗します。チャンクに分割してください。
const BATCH_SIZE = 10;
for (let i = 0; i < allRows.length; i += BATCH_SIZE) {
const batch = allRows.slice(i, i + BATCH_SIZE);
await db.insert(myTable).values(batch);
}
理由:行数 × カラム数が約 100~150 個のパラメーターを超えると、D1 は失敗します。
カラムの命名規則
| コンテキスト | 規則 | 例 |
|---|---|---|
| Drizzle スキーマ | camelCase | caseNumber: text('case_number') |
| 生の SQL クエリ | snake_case | UPDATE cases SET case_number = ? |
| API レスポンス | SQL のエイリアスに合わせる | SELECT case_number FROM cases |
新規プロジェクトのセットアップ
新しいプロジェクト用に D1 データベースを作成する場合は、次の順序で進めてください。
- まず Worker をデプロイする —
npm run build && npx wrangler deploy - D1 データベースを作成する —
npx wrangler d1 create project-name-db database_idをwrangler.jsoncのd1_databasesバインディングにコピーする- 再デプロイする —
npx wrangler deploy - マイグレーションを実行する — ローカルとリモートの両方に適用する