Kizaki
Guides

Migrations

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

Migrations are about workflow discipline, not SQL generation.

Your schema lives in Inspire. Migrations are the repo-tracked record of how environments catch up to that schema. Keep that distinction clear and the system stays straightforward.

For normal schema work:

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

The schema stays authoritative. Migration history stays reviewable.

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

The Local Dev Logic

kizaki dev keeps local work moving, but it does not replace committed migration history. 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 without a migration to explain that drift

Local development is fast, but the project converges through committed migration history, not 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."

This 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:

  • 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.migration, Not Just The Final Schema

The most valuable migration artifact is plan.migration. This 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. Review plan.migration to catch this.

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

The migration command surface is small. 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.migration

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

The latest unapplied committed migration is treated like a draft tip. If it has not been applied locally, kizaki migrate plan rewrites it instead of blindly stacking another migration on top. If multiple pending committed migrations exist, the command fails instead of guessing.

This keeps the workflow practical during active development. You can generate the migration when the change is becoming real, keep iterating, 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.migration 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 being 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 a full stop-the-world event.

You do not need to manage that transition manually. Your responsibility is to keep migration history accurate, reviewed, and committed before deploy.

On this page