Loading...
Loading...
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 skill4agent add jezweb/claude-skills d1-migrationpnpm db:generate.sqldrizzle/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`;defaultALTER TABLE `my_table` ADD COLUMN `new_column` TEXT DEFAULT 'value';.sqlpnpm db:migrate:local
# or: npx wrangler d1 migrations apply DB_NAME --localpnpm db:migrate:remote
# or: npx wrangler d1 migrations apply DB_NAME --remote# 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)"pnpm db:migratePRAGMA 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:migrateCREATE TABLE IF NOT EXISTSALTER TABLE ADD COLUMNIF NOT EXISTSconst 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);
}| Context | Convention | Example |
|---|---|---|
| Drizzle schema | camelCase | |
| Raw SQL queries | snake_case | |
| API responses | Match SQL aliases | |
npm run build && npx wrangler deploynpx wrangler d1 create project-name-dbwrangler.jsoncd1_databasesnpx wrangler deploy