Serverpod Migrations
Serverpod has a migration system that generates SQL for changes to models with
in
. The migrations are applied:
- When the tool is called via the MCP. Typically during development with a running .
- When the server is started with
dart run bin/main.dart --apply-migrations
flag. Typically when running the server in production.
When migrations are needed
- Added, removed, or renamed models or fields in .
- Changed relation fields that alter generated foreign keys.
- Added, removed, or changed indexes.
Migrations are not needed when the project has no database configured (e.g.
with no
section).
Standard flow
The standard flow for creating and applying migrations is simplified when a
is running.
With a running and MCP server
When the server is running from
use the
MCP to:
- Create a migration using the tool.
- Apply the migration using the tool.
ALWAYS use the MCP server if it is available.
ONLY if MCP server fails to connect
When the server is not running from
use the CLI commands to:
- Ensure the code is generated by running .
- Create a migration using the
serverpod create-migration
command.
Editing a generated migration
A migration directory holds
,
and the
,
and
files.
MAY be edited by hand after it is created. Two common reasons:
- Adding a data transformation, so existing rows are migrated along with the schema.
- Turning a destructive change into a non-destructive one, by reaching the same end state through intermediate steps — for example add the new column, backfill it from the old one, then drop the old column, instead of dropping and recreating.
Never edit the other files in the directory.
is the full schema, and the
files are what the next
serverpod create-migration
diffs against, so changing them corrupts every migration created afterwards.
Two rules follow from how migrations are applied:
- A database that has no migrations installed is created from the latest alone and never runs . An existing database applies each newer in order. So the schema an edited ends up with must stay identical to , and data transformations in it only affect databases that upgrade through that version.
- Editing a migration that has already been applied does nothing to the databases that ran it. Create a new migration for those.
On the client side (models with
or
), the same applies to the migration SQL inside the version's
; its definition SQL and JSON files are equally off limits.
Repair migrations
If the database is in an inconsistent state, a repair migration brings it back to a consistent state. It is created by reading the live schema and diffing it against a target migration version, so the database must be reachable.
With a running and MCP server
- Create the repair migration using the tool. Optional arguments: (target migration version, defaults to the latest), , and (required for destructive changes, or when no drift is detected).
- Apply it using the tool, which applies both pending and repair migrations without restarting the server.
ALWAYS use the MCP server if it is available.
ONLY if MCP server fails to connect
bash
# Use the `--mode` flag to specify the run mode
# Use the `--version` flag to specify the target version
# Use the `--force` flag to create a migration with destructive changes
# Use the `--tag` flag to name the migration
serverpod create-repair-migration [--mode production] [--version <name>] [--force] [--tag <tag>]
Apply the repair migration by restarting the server with
dart run bin/main.dart --apply-repair-migration
. Ask the user to run this command.