Skip to Content

Data Migrations

How a schema change reaches a tenant's database.

Each tenant has its own database, so there is no single database to migrate. The record of what has been applied lives in the database itself.

Migrations are SQL files in src/Migrations/postgres and src/Migrations/sqlserver, named <4 digits>_<lower_snake_case>.sql and applied in file-name order by apply.sh:

src/Migrations/apply.sh --engine postgres --conn "postgresql://user:password@host:5432/db" --mode verify
ModeEffect
verifyReports what is pending. Changes nothing. The default.
applyRuns each pending migration, in order, and records it.
baselineRecords pending migrations as applied without running them, for a database that already has the change.

Rules

  • A migration is idempotent. It must be safe over a schema that already contains its change. The self-hosted installer relies on this: on an empty database it loads the schema file and then runs every migration.
  • An applied migration is never edited. Its checksum is recorded, and a mismatch stops the run. Fix a mistake with a new migration.
  • A migration is never renamed. The file name is its identity.
  • No transaction control inside a migration. On PostgreSQL the runner wraps each file in one transaction.

For PostgreSQL the connection is a libpq URI, not a .NET connection string.