drizzle-kit generate Re-Emits an ALTER From a Stale Snapshot
This article may contain affiliate links. Its content is not affected by advertising.
In short
If a column addition isn't reflected in the drizzle snapshot, the next drizzle-kit generate re-emits an ADD COLUMN without IF NOT EXISTS.
If a column addition isn’t reflected in the drizzle snapshot, the next drizzle-kit generate re-emits an ADD COLUMN without IF NOT EXISTS.
Starting with the conclusion
For a column addition with no new table involved, don’t rerun drizzle-kit generate — hand-edit the snapshot (drizzle/meta/*.json) directly to reflect the column definition. Leave it unreflected and the next generate will judge that column “not yet existing,” re-emitting an ADD COLUMN with no IF NOT EXISTS. Applying that ALTER to an environment where the column already exists (via a hand-written migration) fails.
The symptom
On 2026-07-03 (#1205), running drizzle-kit generate to add a new table, class_weekly_schedules, produced a migration file that also re-emitted duplicate ADD COLUMN statements for class_visitors.sort_order and student_callouts.sort_order — columns already added by hand-written migrations 0034 and 0035.
-- (manually removed) drizzle-kit also generated ADD COLUMN for class_visitors / student_callouts
-- sort_order here, but those are owned by hand-written 0034/0035 (ADD COLUMN IF NOT EXISTS, already
-- applied in some environments), so they were removed from this file. sort_order is now captured in
-- the snapshot (meta), so the drift that would re-emit it on future generates is resolved.
0034 and 0035 were written with ADD COLUMN IF NOT EXISTS, but the ALTER drizzle-kit generated this time had none. This round was resolved by manually removing the duplicate section from the SQL file and folding sort_order into the snapshot to close the drift.
The next day, 2026-07-04 (#1220), a similar task came up: adding an is_highlight column to class_visitors and student_callouts. This one involved no new table, so following the same procedure (generate → manually remove the duplicate) would produce a migration file containing nothing but the is_highlight ADD COLUMN, plus a journal entry — leaving behind an empty SQL artifact containing only a comment after removal. The cleanup from last time would become this time’s entire change.
The cause
drizzle-kit generate compares the schema definition (TypeScript) against the most recent snapshot and emits only the diff as SQL. If the snapshot has no record of a column, it’s treated as a “new addition” regardless of whether it already exists in the actual database, and a corresponding ALTER TABLE ... ADD COLUMN gets generated — without IF NOT EXISTS. The hand-written migrations (0034/0035) included IF NOT EXISTS from the start, so they could safely rerun even against an environment where they’d already applied; the generated side makes no such allowance.
The fix
For #1220, instead of rerunning generate, the target snapshot file (drizzle/meta/20260702121657_snapshot.json) was hand-edited directly, adding the is_highlight column definition to both the class_visitors and student_callouts table definitions.
"is_highlight": {
"name": "is_highlight",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
}
The column spec was shaped to match the existing boolean, default-false columns, and inserted right after sort_order in both tables. That the hand edit touches nothing in the journal/SQL lineage is structurally obvious, but whether that hand edit is “consistent with the schema” was confirmed not by eyeballing it but by rerunning drizzle-kit generate. The result: “No schema changes, nothing to migrate” — drizzle’s own signal that schema TS and snapshot now match, with no migration file or journal entry generated.
Preventing recurrence
This choice built on the landmine already stepped on the day before in #1205 (generate emitting a duplicate ALTER, manually removed, leaving behind an SQL artifact containing only a comment). Rather than “step on the same landmine again, then fix it,” #1220 switched to “align the snapshot alone before stepping on the landmine.” What both share is that correctness wasn’t verified by eyeballing either — it was handed off to the deterministic zero-diff confirmation that drizzle-kit generate itself returns.
Frequently asked questions
Q1Why hand-edit the snapshot? Why not just regenerate?
Generate for a column addition with no new table treats that column as 'new,' re-emitting an ADD COLUMN with no IF NOT EXISTS — that can fail an ALTER on an environment where it's already applied. A hand edit skips this path and emits no journal or SQL artifact.
Q2How did you confirm the hand edit was correct?
By running drizzle-kit generate again and confirming it returned "No schema changes, nothing to migrate." That's drizzle's own signal that the schema TS and the snapshot now match — no migration file, no journal entry.
Q3Is it by design that drizzle-kit's ADD COLUMN skips IF NOT EXISTS?
All we have is the observed result: the hand-written migrations (0034/0035) included IF NOT EXISTS, while drizzle-kit generate re-emitting the same columns did not. We don't have grounds to claim this as drizzle-kit's general behavior, so we don't assert it.
Environment verified
- drizzle-orm ^0.45.2 / drizzle-kit ^0.31.10
- Manually removed a duplicate ALTER on 2026-07-03 (#1205); switched to the same fix via snapshot hand-edit on 2026-07-04 (#1220)
What this article is based on
- SQL file lines 13-15commit 77176ae
- JSON file lines 1857-1866commit 6641084
- JSON file lines 2023-2032commit 6641084
Every claim in this article comes from the records above. The repositories we operate are private so we cannot link to them, but which file, which lines, and at which commit we read them is recorded for every article. Nothing here is written from guesswork.