Migrations
Generate SQL from your entities, apply it locally, and release it for deploys.
You never hand-write schema SQL: migrations are derived from your entities, reviewed as files in your repo, and gated before they reach production.
The core workflow
1. Generate. After adding or changing entities, diff them against the last known schema:
This writes a numbered .sql migration into workers/app/database/<database-name>/drizzle/migrations/ (one folder per named database: @default unless you've added more). Read the SQL; it's part of your PR.
2. Apply locally.
--local targets wrangler's local D1 — the same simulated database base develop reads. (For non-D1 databases like PlanetScale, omit --local; the command applies to the configured remote.)
3. Release before deploying. Deploys are blocked until migrations are promoted to the released list:
This updates a release file in your repo — commit it. The gate exists so a schema change is always a deliberate, reviewed act, never a side effect of a deploy.
4. Apply to the target environment when shipping:
Supporting commands
| Command | What it does |
|---|---|
orm migration:check | Verify migration history is consistent |
orm schema:check | Verify entities and migrations agree |
orm migration:drop | Delete a migration file (local only — not a database rollback) |
orm db:reset --local | Wipe local database state for a clean slate |
orm db:studio | Open Drizzle Studio — a browser GUI over your database |
Notes
- Migration state is tracked in the database in a per-worker
__drizzle_migrations_<worker>table, so workers sharing a database keep independent migration histories. For D1, your wranglerd1_databasesconfig must name the same table inmigrations_table(along with the migrations folder inmigrations_dir) — that is the ledgermigration:run --localwrites to, andbase checkfails when the two disagree. - Each named database migrates independently: its own folder, its own history.
- Durable Object databases bundle migrations into settings (
migrations/releasedimports) since there's no external database to reach — see the Durable Objects guide.