zanith

Migrate · 01 — The system

Ship schema changes like you ship code — planned, reviewed, reversible.

Zanith reads your declared schema, diffs it against the live database, and turns the gap into a plan where every op is risk-classified into six levels and gated against a budget you set in CI. It verifies on a shadow database before up touches production, audits every step, and leaves a restorable artifact behind every destructive op.

zanith migrate — fyvault_prod
Migration plan — 2 pending migration(s):
 
Worst risk: destructive
Total risk score: 115
By level: safe=1, medium=1, destructive=1
 
▸ 20260401_add_normalized_email
· [low] addColumn
Risk-scored review before anything touches prod.
5 stages · 1 recovery branch31 op kinds6 risk levels · 21 reasonsshadow-verified upper-step audit37/37 proof · v0.2

02 — What the others ship

The dimensions that matter at 3am.

The four migration tools a production team is most likely to evaluate, against the questions you ask the moment a deploy goes sideways. Names and versions checked April 2026.

CapabilityPrisma MigrateDrizzle KitAtlas (Ariga)Sequelize CLIZanith
Drift detection
spot live-DB drift before plan
partialnoyesnoyes
Auto-fill from drift
generate ops without writing SQL
yesyesyesnoyes
Risk score per op
numeric 0–100, gateable in CI
nonononoyes
Shadow-DB verify
apply on a parallel DB before prod
yesnoyesnoyes
Soft-drop / archive recovery
destructive ops are restorable
nonononoyes
Per-step audit row
every op tracked in DB tables
partialpartialyespartialyes
Bundled web UI
browse rows + apply migrations
partialnononoyes
Down-migrations by N
step back without manual SQL
yespartialyesyesyes
Lifecycle stageSequelize CLIDrizzle KitPrisma MigrateAtlasZanith
graphnoyesyesyesyes
diffnoyesyesyesyes
plannononopartialyes
verifynonoyesyesyes
applyyesyesyesyesyes
recovernonononoyes

Partialmeans the capability exists in some form but lacks the gate or integration. Atlas comes closest — it has shadow-DB and structured audit — but it doesn't score risk per op or ship a recovery layer for destructive ops. The one row no one else fills: restorable destructive ops.

03The pipeline

One frame. Five stages.

Plan, verify, apply, recover, audit — the same morphing product frame you see in the hero. Click a tab to pin it; otherwise it cycles through the proof-sourced output at each stage.

This is what the engine prints — not a mock dashboard. Risk-scored plan output, shadow verify verdicts, per-step apply ledger, recovery artifact codes, and verbose history from the audit tables.

proof-sourced · migrateProofSnippets

zanith migrate — fyvault_prod
Migration plan — 2 pending migration(s):
 
Worst risk: destructive
Total risk score: 115
By level: safe=1, medium=1, destructive=1
 
▸ 20260401_add_normalized_email
· [low] addColumn
Risk-scored review before anything touches prod.

04 — Bundled flow

CLI or Studio tab. Same runner, same audit rows.

Apply from CI or click Apply in Studio — one migration runner, one risk classifier, one set of five audit tables. Recovery artifacts and shadow verify tokens are shared; nothing forks into a second process.

migration architectureone engine · five audit tables
zanith migrateplan · verify · upstudio migrate tabsame risk gatesmigration runnerrisk · shadow verify · recovery artifacts5 audit tables · postgres
05The lifecycle

Four commands. One straight line.

Generate from drift, plan with risk scores, verify on shadow, apply with per-step audit. The frame shows real plan output — what CI greps before anything touches prod.
  • graphthe runtime AST
  • diffstructural delta
  • planrisk-scored ops
  • verifyshadow-DB apply
Full lifecycle — every flag, every artifact path →
zanith migrate plan
Migration plan — 2 pending migration(s):
 
Worst risk: destructive
Total risk score: 115
By level: safe=1, medium=1, destructive=1
 
▸ 20260401_add_normalized_email
· [low] addColumn
⚠ [medium] addUnique
▸ 20260402_drop_legacy_uuid
06Risk model

Six named levels. One numeric budget.

Every one of 31 op kinds is classified into a level with a score on 0–100, tagged with one or more of 21 reason codes. CI sets a budget; the planner refuses to cross it.
51535608095
safescore 5

Additive, reversible, no data at stake.

lowscore 15

Cheap to apply, easy to reverse.

mediumscore 35

Can fail on real data, or breaks readers.

highscore 60

Likely to fail or rewrite the table.

destructivescore 80

Permanently deletes data without a flag.

blockedscore 95

Reserved ceiling for row-count-aware refusals.

7 gates between plan and prod
Risk budgetDestructive opt-inPreflight probesAdvisory lockPer-migration transactionShadow-verifiedDry run
Full classifier →
risk classifier
safe · score 5
CreateIndex & constraintAlterDropSecurity (RLS)
07Recovery

A drop is not a delete. Yet.

Every destructive op leaves a restorable artifact. The column or table is renamed aside or archived into _zanith_shadow, and stays restorable until you run cleanup. None of Prisma, Drizzle, Atlas, or Sequelize ship this.
soft_drop_columnRenames the column to _zanith_dropped_<col>_<id>. Restore = rename back. Instant.
soft_drop_tableRenames the table aside. Restore = rename back. Instant, zero copy.
archive_columnCopies the table into _zanith_shadow, then drops the column. Stores row count + checksum.
archive_tableMoves the whole table into _zanith_shadow and renames it. Instant — no row copy.
rebuild_tableAfter a copy-swap rebuild, keeps the old table as _zanith_dropped_<table>_<id>.

7 recover verbs plus cleanup — no new mental model, no backup-restore dance.

Artifact table, checksums, all 7 verbs →
zanith recover
archive → checksum
AAA-001pending
BBB-002pending
CCC-003pending
DDD-004pending
EEE-005pending