Stale Migrations
A stale migration occurs when the applied migrations in the target don't match the expected order from the source. The library detects this and returns ErrStaleMigrationDetected instead of silently running in an inconsistent state.
How It Happens
The most common scenario is parallel development. Two developers create migrations on separate branches:
main: migration_1
branch A: migration_1 → migration_2_create_orders
branch B: migration_1 → migration_3_add_user_emailBranch B gets merged and deployed first. The target now has migrations 1 and 3 applied. When branch A is merged, migration 2 appears in the source — but it's older than the already-applied migration 3.
The source list is [1, 2, 3], but the target has [1, 3]. Migration 2 was skipped, and running it now could be unsafe because migration 3 may depend on a database state that assumes 2 was never applied.
How Detection Works
During planning, the MigratePlanner compares the applied migrations (from the target) against the full migration list (from the source) in order. If the applied list doesn't match the source list position by position, it means a migration was skipped:
Source: [1, 2, 3]
Target: [1, 3]
↑
Position 1 in target is "3", but position 1 in source is "2"
→ ErrStaleMigrationDetectedThis check runs before any migration is executed, so the database is never left in a partially-applied state from a bad plan.
What To Do
When you hit ErrStaleMigrationDetected, you need to decide how to reconcile the ordering:
-
If the skipped migration is safe to apply — manually apply it, mark it in the target, then re-run. The key question is whether the skipped migration conflicts with any migration that was already applied after it.
-
If the skipped migration conflicts — you may need to create a new migration that combines or replaces the skipped one, accounting for the current database state.
-
Prevention — use a coordination strategy in your team to avoid timestamp collisions. Since migration IDs are timestamps down to the second (
YYYYMMDDHHmmss), conflicts are rare but not impossible when multiple branches create migrations around the same time.
Why Not Just Run It?
Some migration tools silently run skipped migrations. This library treats it as an error because:
- A migration written for an earlier state may break when applied to a later state. For example, a migration that adds a column might fail if a later migration already altered or dropped that table.
- Silent reordering can cause subtle data corruption that's hard to trace back to a migration ordering issue.
- Failing explicitly gives you the chance to inspect the situation and make an informed decision rather than hoping it works out.