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.
The Recommended Workflow
For normal schema work, the path should be:
- change Inspire
- iterate locally until the schema shape is right
- run
kizaki migrate plan - review
plan.inspire - run
kizaki migrate apply - 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 applyThe 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_datemigration "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.inspirekizaki 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: noneThink 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.inspirelike code, not like generated trash - commit migration files with the schema change itself
- use
statuswhen 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.