npx skills add ...
npx skills add jezweb/claude-skills --skill d1-migration
Cloudflare D1 migration workflow: generate with Drizzle, inspect SQL for gotchas, apply to local and remote, fix stuck migrations, handle partial failures. Use when running migrations, fixing migration errors, or setting up D1 schemas.
npx skills add jezweb/claude-skills --skill d1-migration
Guided workflow for Cloudflare D1 database migrations using Drizzle ORM.
This creates a new .sql file in drizzle/ (or your configured migrations directory).
Always read the generated SQL before applying. Drizzle sometimes generates destructive migrations for simple schema changes.
If you see this pattern, the migration will likely fail:
Cause: Changing a column's default value in Drizzle schema triggers full table recreation. The INSERT SELECT references the new column from the old table.
Fix: If you're only adding new columns (no type/constraint changes on existing columns), simplify to:
Edit the .sql file directly before applying.
Always apply to BOTH local and remote before testing. Local-only migrations cause confusing "works locally, breaks in production" issues.
When a migration partially applied (e.g. column was added but migration wasn't recorded), wrangler retries it and fails on the duplicate column.
Symptoms: pnpm db:migrate errors on a migration that looks like it should be done. PRAGMA table_info shows the column exists.
CREATE TABLE IF NOT EXISTS — safe to re-runALTER TABLE ADD COLUMN — SQLite has no IF NOT EXISTS variant; check column existence first or use try/catch in application codeD1's parameter limit causes silent failures with large multi-row INSERTs. Batch into chunks:
Why: D1 fails when rows x columns exceeds ~100-150 parameters.
| Context | Convention | Example |
|---|---|---|
| Drizzle schema | camelCase | caseNumber: text('case_number') |
| Raw SQL queries | snake_case | UPDATE cases SET case_number = ? |
| API responses | Match SQL aliases | SELECT case_number FROM cases |
When creating a D1 database for a new project, follow this order:
npm run build && npx wrangler deploynpx wrangler d1 create project-name-dbwrangler.jsonc d1_databases bindingnpx wrangler deploy