Kizaki
ReferenceInspire

Migrations

Evolve Inspire schemas through committed migration history, reviewed plans, and a dev loop that stays aligned with that history.

Migrations are the reviewed history of how your database catches up to the schema declared in Inspire.

The schema is the source of truth. You change Inspire, generate a migration plan, review it, and commit the result. You do not hand-author SQL migrations.

What A Migration Is

A migration is a repo-tracked transition between two schema states.

  1. Inspire declares the target schema
  2. kizaki migrate plan compares current schema to the latest committed snapshot
  3. Kizaki writes a migration directory under migrations/<NNNN_slug>/
  4. You review the generated plan before applying and committing

Artifacts

ArtifactPurpose
.inspire filesDeclares where the schema should end up
plan.migrationDescribes what changed
snapshot.jsonCaptures the compiled schema state for historical comparison

Directory Shape

migrations/
  0001_initial/
    plan.migration
    snapshot.json
  0002_add_due_date/
    plan.migration
    snapshot.json

Example plan.migration

migration "0002_add_due_date" {
  add Task.dueDate: datetime?
  add Task.status: TaskStatus = Todo
  rename Task.ownerId -> Task.assigneeId
}

Development Workflow

kizaki dev And Migration History

kizaki dev keeps local development moving, but committed migrations remain the authority. The dev stack:

  • Compares your source schema to the latest committed migration snapshot
  • Auto-applies committed pending migrations to the local database
  • Fails if your source schema has moved ahead and you have not generated the next migration
$ kizaki dev

Starting local stack...
Applying committed migrations...
  0001_initial
  0002_add_due_date

Source schema is ahead of committed migration history.
Run `kizaki migrate plan` before continuing.

Generating A Migration

Once a schema change stabilizes:

  1. Edit Inspire
  2. Iterate locally until the 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
$ kizaki migrate plan --name add_due_date

Generated migrations/0002_add_due_date/plan.migration
Generated migrations/0002_add_due_date/snapshot.json

Draft Tip Behavior

If the latest committed migration has not been applied locally, plan rewrites it instead of creating a new numbered migration. If multiple committed migrations are pending, planning fails.

$ kizaki migrate plan

Latest committed migration is still unapplied locally.
Rewriting migrations/0003_rework_tasks/ instead of creating 0004.

Commands

kizaki migrate plan
kizaki migrate apply
kizaki migrate dry-run
kizaki migrate status

kizaki migrate plan

Diffs the resolved Inspire workspace against the latest committed snapshot.json. Writes the next migration plan. Surfaces ambiguous cases through [RESOLVE] markers.

$ kizaki migrate plan

Comparing source schema to migrations/0002_add_due_date/snapshot.json...
Generated migrations/0003_split_assignee/plan.migration

kizaki migrate apply

Applies pending committed migrations in order to the local database.

$ kizaki migrate apply

Applying 0003_split_assignee...
Migration applied successfully.

kizaki migrate dry-run

Shows generated SQL and impact without executing. Useful before deploys or for destructive/ambiguous changes.

$ kizaki migrate dry-run

Migration: 0003_split_assignee
- rename Task.ownerId -> Task.assigneeId
- add Task.assignedAt: datetime?

No changes applied.

kizaki migrate status

Reports the latest committed migration, latest applied migration, and source drift.

$ kizaki migrate status

Latest committed: 0003_split_assignee
Latest applied:   0003_split_assignee
Source drift:     none

Reviewing plan.migration

Treat the plan as code review material. Check:

  • Did the diff detect a rename, or did it drop and re-add?
  • Did an additive change stay additive?
  • Is a destructive operation intentional?
  • Are any [RESOLVE] markers still present?
  • Does the plan match the product change you intended?
migration "0004_rework_profile" {
  [RESOLVE] rename User.fullName -> User.displayName
  add User.avatarUrl: string?
}

If [RESOLVE] markers remain, the migration is not ready.

When A Migration Is Required

A migration is required when the database schema changes:

  • Adding or removing entities
  • Adding, renaming, or removing fields
  • Changing indexes or constraints
  • Changing enums

No migration needed for runtime-only changes:

  • Policy changes
  • Route changes
  • Auth configuration that does not alter stored schema
  • Runtime enforcement behavior

Rule: if Postgres needs to change shape, you need a migration.

Good Migration Hygiene

  • One conceptual schema change per migration
  • Generate the migration promptly after the change stabilizes
  • Review plan.migration before applying
  • Commit the migration directory with the schema change
  • Avoid letting source drift far ahead of committed history

Zero-Downtime Deploys

The platform applies migrations as part of deploy and coordinates the schema transition with the new application version. Additive changes are straightforward. Renames and drops are staged so old and new app code are not forced through the same query assumptions simultaneously.

Your responsibility remains the same: generate and review the migration carefully.

Related guide: Migrations

On this page