Skip to content

Migrations

When you change flatstack/schema.ts, Flatstack turns the change into a SQL migration and applies it to your environment’s database before the new code goes live. Until the CLI ships, migrations can be applied through the API below.

Generating a migration

flatstack db diff compares flatstack/schema.ts with the last snapshot and writes the difference as a new file in flatstack/migrations/, named 0000_label.sql, 0001_label.sql and so on. Commit these files with your code. Never edit one that has been applied: add a new migration instead.

If a column or table looks renamed, the diff can’t tell a rename from a drop and an add. It stops and asks you to make the change in two steps.

Applying migrations

flatstack deploy sends every migration file with the bundle. Flatstack applies the ones the environment hasn’t had yet, in name order, and records each one. Then the code goes live.

Pending migrations are applied all or nothing:

  • D1: Flatstack takes a Time Travel bookmark first and restores it if any statement fails.
  • Postgres: the migrations run in one transaction, rolled back if any statement fails.

If a migration fails, the database is exactly as it was, the deploy fails and your previous code keeps serving. The error is 422 migration_failed, with details.migration, details.statement, details.error and, for a deploy, details.deployId.

Destructive changes

Dropping a table or column, changing a column’s type and deleting rows can lose data, so these migrations need confirming. Without it, the request returns 409 destructive_migration, lists each change in details.migrations, and changes nothing. Confirm with --allow-destructive (allowDestructive: true in the API). Destructive migrations are recorded in the audit log as migration.destructive_applied.

Conflicts

A request returns 409 migration_conflict, and changes nothing, if:

  • a migration that was applied is missing from your files,
  • an applied migration’s contents changed, or
  • a new migration sorts before one already applied.

API

Request Who What it does
POST /v1/projects/{id}/migrations Owners, admins, developers, deploy tokens { "migrations": [{ "name", "sql" }], "environment"?, "allowDestructive"?, "dryRun"? }. Applies pending migrations without deploying code. Returns applied, appliedNow and pending (with each pending migration’s destructive changes).
POST /v1/projects/{id}/deploys Owners, admins, developers, deploy tokens Accepts the same migrations and allowDestructive alongside script.

Use dryRun: true to see what would run, and what’s destructive, without changing anything.

As Markdown: apps/migrations.md