---
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.
