Migrations
Schema migrations in Xema are workflow-orchestrated and isolated per schema. Every migration run records which of the platform's two runners applied it: one applies the migration files a biome ships inside its bundle, the other applies a typed schema-change plan generated by the platform.
Migration runners
Two are implemented, and a MigrationRun records which one applied it.
MigrationRunnerKind also declares drizzle and flyway, but nothing emits
them — they are placeholders, not supported tooling. Adding a runner is a
platform change, not configuration.
The bundle-applying runner is handed a workspace and a short-lived connection, and reports the outcome of applying every pending migration in it:
1interface MigrationRunInput {
2 connectionUrl: string; // short-lived credential URL (see Connections)
3 workspaceDir: string; // the biome's migration bundle on the executor
4 env: Record<string, string>;
5}
6
7interface MigrationRunResult {
8 exitCode: number;
9 output: string;
10}The platform does not read the migration files themselves — it hands the runner a workspace and a short-lived connection and records the exit code and output on the MigrationRun row.
Default migration runner (v1)
The default runner. It:
- Connects to the schema using the provided
connectionUrl. - Runs all pending migrations in
migrationsPathagainst the target schema. - Records the migration history in the migration history table inside the target schema.
- Records the outcome — the runner used, the applied migrations, and any failure — on a
MigrationRunrow carrying aMigrationStatus.
Migration files in the biome bundle are organized by timestamp and name:
1biome/
2 migrations/
3 20260527_001_create_reviews/
4 migration.sql
5 20260527_002_add_comments/
6 migration.sql
7 schema.migrationWhen migrations run
Migrations run as part of three platform workflows:
| Entry point | When triggered | What it does |
|---|---|---|
ProvisionDatabaseWorkflow | At org provisioning | Creates the org database and its first schema |
EnsureSchemaWorkflow | At biome install | Ensures the biome's schema exists on the org database |
RunMigrationsActivity | At biome boot and on version update | Applies the biome's pending migrations |
| Promote-to-prod | On an app production deploy | Applies pending migrations to the prod schema (see App Studio Dev/Prod) |
All of them record the runner they used on the MigrationRun row. The workflows are orchestrated by the Xema Workflow Runtime, which provides retry, timeout, and observability; the migration activity raises typed failures (MigrationFailedError, MigrationTimeoutError) rather than reporting a partial success.
Migration failure behavior
If a migration fails:
- The workflow marks the migration step as
FAILED. - The schema is left in the partially-migrated state (the database does not auto-rollback DDL across statements).
- The biome remains in
schema-migration-failedstate — it can read existing data but cannot write to newly-expected columns. - The org admin receives an alert with the failed migration SQL and the database error.
To recover: fix the migration SQL, publish a new biome version, and re-run the migration.
Manual migration control
For migrations that require careful sequencing (large table rewrites, zero-downtime schema changes), the migration can be marked manual-only in the biome's migration manifest:
1{
2 "migration": "20260527_003_reindex_reviews",
3 "mode": "manual-only",
4 "instructions": "Run CONCURRENTLY to avoid table lock. See ops runbook."
5}Manual-only migrations are skipped by the automatic runner and surfaced in the org admin dashboard with the instructions. An org admin must run them explicitly — from the org admin dashboard, or with the Shell's db migrate command.
Previous: ← Provisioning
Next: Connections →