--- title: Adopt drizzle generate+migrate workflow (retire db:push on MariaDB) date: 2026-06-05 priority: high --- # Adopt drizzle generate+migrate workflow (retire db:push on MariaDB) `drizzle-kit push` produces a FALSE destructive diff against the populated MariaDB and must not be used for incremental schema changes. Root cause: drizzle-kit 0.31.10 (latest) has no `mariadb` dialect; `drizzle.config.ts` uses `dialect: 'mysql'` against MariaDB 11.8 (collation `utf8mb4_uca1400_ai_ci`). Live-DB introspection through the mysql lens misreads MariaDB metadata (timestamp defaults as `current_timestamp()`, undetected PKs), so push schedules `MODIFY COLUMN` no-ops, bogus `ADD PRIMARY KEY`, and `truncate`/recreate. Observed during Phase 3 / plan 03-01 Task 5: a plain "add calendar_outbox + object_url" push emitted `truncate table calendars/calendar_events/users` (would have wiped 503 events). Worked around by hand-applying the additive DDL directly. push only ever worked because the first run was against an empty DB. ## Goal Move schema changes onto `drizzle-kit generate` → `drizzle-kit migrate`. `generate` diffs schema.ts against drizzle's JSON snapshots (`apps/api/src/db/migrations`), never the live DB, so the introspection bug can't fire. Generated `CREATE TABLE`/`ADD COLUMN`/`CREATE INDEX` SQL is MariaDB-compatible. ## Tasks - [ ] Confirm live DB matches schema.ts exactly (it does as of 2026-06-05: calendar_outbox + object_url were hand-applied; all 5 tables present). - [ ] Run `pnpm --filter @familysync/api run db:generate` once to produce the baseline migration + `meta/_journal.json` + `0000_*.sql` snapshot. - [ ] Seed the `__drizzle_migrations` table so the baseline is marked applied (the live DB already matches it — `migrate` must NOT re-run the CREATE statements). - [ ] Repoint workflow off push: change/remove the `db:push` script in `apps/api/package.json`; make `db:generate` + `db:migrate` the canonical path. - [ ] Update CLAUDE.md (drizzle/migration guidance) and the GSD plan/SUMMARY conventions that currently assume `db:push`. - [ ] Verify end-to-end with a throwaway additive column change: generate → migrate → confirm only the delta runs, no truncate. See memory: drizzle-mariadb-push-unsafe.