Kizaki
Guides

Migrations

Use migrations as the reviewed, committed history of schema changes while letting the dev loop stay fast locally.

The most important thing to understand about migrations in Kizaki is not SQL generation. It is workflow discipline.

The schema still lives in Inspire. Migrations are the repo-tracked record of how environments catch up to that schema. If you keep that distinction clear, the migration system feels straightforward.

For normal schema work, the path should be:

  1. change Inspire
  2. iterate locally until the schema shape is right
  3. run kizaki migrate plan
  4. review plan.inspire
  5. run kizaki migrate apply
  6. commit the migration directory with the schema change

That is the healthy center of the workflow. The schema stays authoritative, and migration history stays reviewable.

$ kizaki migrate plan --name add_due_dates
$ kizaki migrate apply

The Local Dev Logic

This is where people usually get confused, so it is worth being explicit.

kizaki dev is designed to keep local work moving, but it does not replace committed migration history. In the current repo behavior, the local dev flow:

  • applies committed pending migrations to your local database
  • compares your source schema to the latest committed snapshot
  • fails closed if your source has moved ahead in a schema-affecting way and you have not generated the migration that explains that drift

That means local development is fast, but the project still converges through committed migration history rather than through hidden machine-local schema state.

$ kizaki dev

Applying committed migrations...
Source schema is ahead of committed history.
Run `kizaki migrate plan` to continue.

Do Not Treat Migration Files As Optional Cleanup

One easy mistake is to think “I’ll do the migration part later.”

That usually creates one of two problems:

  • your source schema drifts ahead of committed history
  • one migration later tries to explain too many unrelated changes at once

A better habit is:

  • once the schema change is real, generate the migration
  • once the migration is generated, review it immediately

This keeps every migration small enough to understand.

A Healthy Small Change

entity Task {
  title: string,
  dueDate: datetime?,
}
$ kizaki migrate plan --name add_due_date
migration "0002_add_due_date" {
  add Task.dueDate: datetime?
}

Review plan.inspire, Not Just The Final Schema

The most valuable migration artifact is plan.inspire.

That is where you verify that the system understood your change correctly:

  • a rename is really a rename
  • a new field is really additive
  • a dropped field is actually intentional
  • any [RESOLVE] markers are handled before you apply

This is the difference between “the schema changed” and “the database transition is safe and legible.”

Review For Intent, Not Just Syntax

Good:

migration "0003_rename_owner" {
  rename Task.ownerId -> Task.assigneeId
}

Suspicious:

migration "0003_rename_owner" {
  drop Task.ownerId
  add Task.assigneeId: __User.id
}

Those two plans mean very different things. That is why plan.inspire deserves review.

Use plan, apply, dry-run, And status Deliberately

The migration command surface is small, and each command answers a different question.

kizaki migrate plan

Use this when you changed the schema and need the migration history to catch up.

It answers: what is the transition from the latest committed snapshot to the current Inspire schema?

$ kizaki migrate plan
Generated migrations/0004_add_status/plan.inspire

kizaki migrate apply

Use this when you want the local database to move forward through the committed migration history.

It answers: is the local database now aligned with the migration history I reviewed?

$ kizaki migrate apply
Applying 0004_add_status...
Done.

kizaki migrate dry-run

Use this when you want to inspect what would happen without executing it.

It answers: does this transition look safe before I actually apply or deploy it?

$ kizaki migrate dry-run
Migration 0004_add_status
- add Task.status: TaskStatus = Todo
No changes applied.

kizaki migrate status

Use this when you are unsure whether source, committed history, and local state still agree.

It answers: what is committed, what is applied, and where is the drift?

$ kizaki migrate status
Latest committed: 0004_add_status
Latest applied:   0004_add_status
Source drift:     none

Think Of The Latest Unapplied Migration As Draft History

One useful current behavior is that the latest unapplied committed migration is treated like a draft tip.

If it has not yet been applied locally, kizaki migrate plan rewrites that latest unapplied migration instead of blindly stacking another migration on top. If multiple pending committed migrations exist, the command fails instead of guessing.

That keeps the workflow practical during active development. You can generate the migration when the change is becoming real, keep iterating a bit, and still end up with one coherent migration instead of a pile of noise.

$ kizaki migrate plan
Rewriting migrations/0005_rework_roles/ because it is still unapplied locally.

What Good Migration Hygiene Looks Like

  • keep migrations focused on one conceptual schema change when practical
  • generate them soon after the schema change stabilizes
  • review plan.inspire like code, not like generated trash
  • commit migration files with the schema change itself
  • use status when you suspect source or local state has drifted

If migrations start feeling painful, the problem is usually not “the migration system is too strict.” It is usually that too much change accumulated before the transition was made explicit.

Deploys, Briefly

At deploy time, the platform coordinates schema changes with the new application version so migrations can roll out without treating every schema change like a full stop-the-world event.

You do not need to manage that transition manually. The practical responsibility on your side is to keep migration history accurate, reviewed, and committed before deploy.

On this page