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.
The Recommended Workflow
For normal schema work:
- change Inspire
- iterate locally until the schema shape is right
- run
kizaki migrate plan - review
plan.migration - run
kizaki migrate apply - 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 applyThe 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_datemigration "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.migrationkizaki 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: noneThink 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.migrationlike 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 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.