Companion code for the Flyway vs Liquibase article: checksum validation, out-of-order and repeatable migrations, baselining an existing schema, Flyway Community's undo/diff/deploy stubs, concurrent-startup locking for both tools, Liquibase changeset identity and rollback (auto-generated vs explicit), a verified Liquibase 5.0.3 filename-caching defect, the new OSS license service, the FSL license change, and running both tools against one database. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Q6XdRjtsp4862EM44T7i9a
4.8 KiB
4. Out-of-order migrations
← 3. Checksum validation · Index · Next: 5. Repeatable migrations →
Two branches, both adding "the next migration": one ships V3 and merges quickly, the other's
V2 sits in a slow-to-review pull request and lands afterward. By the time V2 merges, every
environment that deployed the first branch already has V3 applied. What happens when V2
finally shows up?
FlywayOutOfOrderTest
reproduces exactly this: V1 and V3 apply on a first startup, then V2__add_note_length_check.sql
is dropped in afterward, and a second startup runs against the same database.
The common assumption — that Flyway just quietly skips the late-arriving lower version and carries on — is wrong. The whole application fails to start:
context failed to start: FlywayValidateException: Validate failed: Migrations have failed validation
Detected resolved migration not applied to database: 2.
To ignore this migration, set -ignoreMigrationPatterns='*:ignored'. To allow executing this migration, set -outOfOrder=true.
(from docs/output/03-flyway-out-of-order.txt; this test was
originally written expecting the silent-skip behaviour, and the real run corrected it)
Validation runs before migration, and by default (spring.flyway.out-of-order=false) a resolved
migration with a version lower than the highest already-applied one is treated as a validation
failure, not a no-op. Nothing gets applied and the context never comes up.
same history, out-of-order=true
Setting spring.flyway.out-of-order=true is the fix the error message itself names, and a third
startup in the same test confirms what it actually does: V2 runs, and the history table keeps it
in real application order — rank 3, version 2, sitting after rank 2's version 3 — Flyway does not
retroactively renumber or reorder anything:
installed_rank | version | description | success
---------------+---------+-------------------------------------------+--------
-1 | NULL | << Flyway Schema History table created >> | true
1 | 1 | init | true
2 | 3 | add note index | true
3 | 2 | add note length check | true
(from the same transcript)
Going deeper
outOfOrderis a blunt, global switch — turning it on doesn't just allow the one late migration you're expecting, it allows any lower-numbered migration to slot in from then on. Flyway's own docs call this out as reducing reproducibility, anddocs/output/03-flyway-out-of-order.txt's third-startup log line says so verbatim:outOfOrder mode is active. Migration of schema may not be reproducible.ignoreMigrationPatterns(rel="nofollow") — the error message's other suggested fix, for permanently ignoring a specific migration instead of relaxing ordering globally.- A team that hits this regularly is usually missing a CI check that fails a PR when its migration's version number is lower than what's already merged to main — cheaper than relying on
outOfOrderat all.