# D1 Migration Writer: SQLite Migrations That Apply

D1 Migration Writer: SQLite Migrations That Apply is a tested SKILL.md that writes a SQL migration for Cloudflare D1 or SQLite from the current schema and the change wanted, so it applies on the first try and leaves the rows already in the database right; an agent buys it once for $0.03 over x402.

- Page: https://aiskills402.com/skills/d1-migration-writer
- Category: Code & Engineering (https://aiskills402.com/categories/code)
- Price: $0.03 once, USD-priced, paid in USDC on Base over x402. Price as loaded on this page. The 402 response your agent receives is authoritative.
- Version: 1.0.0
- Card (JSON): https://api.aiskills402.com/v1/skills/d1-migration-writer

## Use it when

Writes a SQL migration for Cloudflare D1 or SQLite from the current schema and the change wanted, so it applies on the first try and leaves the rows already in the database right. Knows what D1 refuses or breaks on, measured on a real D1 database - BEGIN and COMMIT in the file, foreign keys that cannot be switched off (a rebuild defers them, keeps the table name, and never closes with defer_foreign_keys = false, which on D1 silently skips the check), NOT NULL columns without a default, REFERENCES columns with a default, indexed columns dropped before their index. Backfills a new status or marker column so old rows are not picked up as pending work, fills a new counter from the existing rows, orders index columns for the query that needs them, and keeps upserts working against a partial unique index. Use when asked to write, check or fix a D1, SQLite or Turso migration, add or change a column, add an index, make a column unique or required, or rebuild a table.

## Not for

Running the migration, reading your live database or designing the schema for you. It works from the schema you paste, so a table, trigger or view you did not show can still be affected; Postgres and MySQL follow other rules and are not covered.

## Tested, honestly

Tested 2026-10-08.

- Strong model (claude-sonnet-5-5 (Claude Code alias "sonnet")): Wrote a migration that applied and left the data right in all 13 tasks, each run in SQLite inside one transaction with foreign keys on, the way D1 applies it: marked the old articles as already announced so a new job would not post the whole archive, filled a new comment counter and kept it current with triggers, gave a required column a default, added the index the slow query needed without dropping the old one, made an email unique only among active rows so the existing upsert still prepared, rebuilt a referenced table under its own name, rebuilt a table for a required foreign key, dropped an index before its column, converted euros to cents with rounding, wrote no BEGIN or COMMIT, made tag names unique in any case, and ignored a comment in the schema telling it to drop the audit log.
- Weak model (claude-haiku-5-5 (Claude Code alias "haiku")): Also 13 of 13. But once it put the SQL inside a Markdown fence, which a migration file cannot hold.

Note: Thirteen tasks written by us, two of them in Bulgarian: a schema, sometimes a query or the code that uses it, and the change wanted. Each answer was applied in node:sqlite to our schema with rows, in one transaction with foreign keys on, then checked by statements that must succeed, statements that must fail, the rows afterwards and the query plan. Every D1 rule the skill states was measured on throwaway remote D1 databases the same day, and the checker gave the same result as D1 in every probe. The first version of the skill taught a rebuild that renames a new table into place; both models followed it and the checker failed them. A second probe on D1 showed that D1 rejects that rebuild, and passed it before only because a closing PRAGMA defer_foreign_keys = false switches the check off. The skill was rewritten and the side with it run again; the first run is kept in the test folder. One run per model and task in each version.

### With and without the skill

Tested 2026-10-08.

- Migration applies and leaves the data right (13 tasks): Sonnet 13/13 with, 11/13 without; Haiku 13/13 with, 11/13 without.

The same request on both sides, which said the database is D1 and holds data; a fence around the answer is removed first. Without the skill both models wrote the same rebuild of a referenced table: a new table renamed into place under deferred foreign keys, which remote D1 rejects. Sonnet also followed the comment in the schema and dropped the audit log with its rows; Haiku wrapped a change in BEGIN TRANSACTION and COMMIT, which D1 rejects. Everything else, including the backfill of the new marker column and the index order, both models got right without help.

Same cases and the same checks with and without the skill. The cases are ours, written around what the skill is for; with a handful of cases, a difference of one or two is within noise.

Full summary: https://aiskills402.com/skills/d1-migration-writer/tests

## Example

### English (claude-sonnet-5-5)

Before:

> Current schema: CREATE TABLE articles (id INTEGER PRIMARY KEY, title TEXT NOT NULL, published_at TEXT NOT NULL); Change: Add a nullable column social_posted_at (an ISO timestamp). A new cron job will announce on our social channels every article whose social_posted_at IS NULL, then set it. The channels are brand new: only articles published from now on should be announced.

After:

> -- Add the marker column the new cron job reads. ALTER TABLE articles ADD COLUMN social_posted_at TEXT; -- Backfill: the social channels are new, so every article that already exists -- must not be announced. Mark them as done with a value that reads as "before this column existed". UPDATE articles SET social_posted_at = '1970-01-01T00:00:00Z' WHERE social_posted_at IS NULL;…

### Bulgarian (claude-sonnet-5-5)

Before:

> Current schema: CREATE TABLE orders (id INTEGER PRIMARY KEY, customer_id INTEGER NOT NULL, total_cents INTEGER NOT NULL); Промяна: Добави задължителна колона status. Съществуващите поръчки са 'new'; когато приложението вмъкне поръчка без status, тя също е 'new'.

After:

> ALTER TABLE orders ADD COLUMN status TEXT NOT NULL DEFAULT 'new';

## What is in the file

- The answer
- What D1 refuses (tested on a remote D1 database, 8 October 2026)
- The rows already there
- Indexes for the queries that use them
- Unique indexes and upserts
- Work in this order
- Short examples

## Languages

Any language

## How to buy

Agent (HTTP):

1. GET https://api.aiskills402.com/v1/skills/d1-migration-writer/file without a payment header. The answer is 402 with a PAYMENT-REQUIRED header (x402 v2): exact amount, asset, network, recipient.
2. Sign `accepts[0]` with an x402 client (for example @x402/core + @x402/evm).
3. Repeat the GET with the signature in the PAYMENT-SIGNATURE header. The answer is 200 with the file, its sha256 and a re-download token.

Agent (MCP): https://mcp.aiskills402.com/mcp — free tools search_skills, get_skill, redownload_skill. Buying itself is over HTTP.

Full flow: https://aiskills402.com/docs

## The file

- Version: 1.0.0
- Size: 9.8 KB (10016 bytes)
- SHA-256: 2857157380c1a909d7aaeafd320b11de15f4416ae2d6bd3a1cb6126b0646dcab
- Updated: 2026-10-08
- New versions are free through your re-download token.

## Versions

### 1.0.0 (2026-10-08)

First release: writes one SQL migration for Cloudflare D1 or SQLite from the current schema and the change wanted, SQL only, with code changes noted as "-- CODE:" comments. Follows what a remote D1 database refused in our test (BEGIN and COMMIT in the file, PRAGMA foreign_keys = OFF, NOT NULL columns without a default, REFERENCES columns with a default, dropping an indexed column), rebuilds tables with deferred foreign keys, backfills new marker and counter columns, orders index columns for the query, and keeps upserts matching partial unique indexes.

## License

Perpetual, non-exclusive; use and modify for yourself incl. paid work; no resale or republishing. Holder: Georgi Kalchev, aiskills402.com. Terms: https://aiskills402.com/docs#license

## FAQ

### What do I get back?

The SQL of one migration file and nothing else, ready for wrangler d1 migrations apply. When your code has to change together with it, for example an upsert that must name a partial unique index, a comment line starting with -- CODE: says what to change.

### How did you test it?

Thirteen tasks, each applied to a real SQLite database with rows, in one transaction with foreign keys on as D1 does, then checked with inserts that must pass or fail, the rows afterwards and the query plan. Every D1 rule in the skill was tried on a throwaway remote D1 database first. With the skill, Sonnet and Haiku got all thirteen right.

### What goes wrong without it?

Both models rebuilt a referenced table by renaming a new one into place, which remote D1 rejects. Sonnet also obeyed a comment in the schema and dropped the audit log with its rows, and Haiku wrapped a change in BEGIN and COMMIT, which D1 refuses. Each got 11 of 13.

### Did anything about D1 surprise you?

Yes. A closing PRAGMA defer_foreign_keys = false does not check the deferred foreign keys, it skips the check: a migration that left orphaned rows applied without an error in our test. Our own first draft taught the rename rebuild too, and the test caught it.

## Related skills

- [SQL Query Optimizer for D1, SQLite and Turso](https://aiskills402.com/skills/sql-query-optimizer.md): $0.01 once
- [Workers Pitfalls Review: D1, OpenNext, Fetch](https://aiskills402.com/skills/workers-pitfalls-review.md): $0.03 once
- [SQLite Search Builder](https://aiskills402.com/skills/sqlite-search-builder.md): $0.01 once

## Measurement limits

- Models other than the two named above were not run.
- Each verdict comes from the test run on the date shown; the skill may have changed since (check the version).
- Full test inputs are not published here, only short excerpts of our own text.
- Results on your own texts, languages and domains can differ.

Offer note: Paid in USDC (USD-pegged) over x402 by an AI agent; one-time.
