A staged migration test can stop at an intermediate version to check whether an older application write remains valid.
Spring Boot migration target: test an old writer before closing the schema
V2 accepts the old shape
The first Boot context targets migration version 2. Its receipt table has a nullable tenant_id. The test inserts receipt 102 with only receipt_id and amount_minor. Both that row and the V1 seed row have null tenant_id. A new reader that assumes ownership is already populated would be wrong during this overlap.
The second context targets version 3 against the same H2 URL. Flyway backfills those rows and tightens tenant_id to NOT NULL. The test counts zero null owners and rejects an old-shape insert. It then accepts receipt 104 with east as tenant. The contract phase must follow an application rollout that already writes the new field.
This is a version step, not live coexistence
The test closes the first context before opening the second. It does not run old and new processes at the same time. A real release should start both versions against a disposable target-engine database while traffic continues, then verify reads, writes and rollback options at each version.
V3 backfills a tiny test table in one statement. A large table may need bounded, resumable work with business-reviewed tenant assignment. A NOT NULL constraint can enforce presence, not correctness of that assignment.
Checked source
spring.flyway.target=2
# Old write omitting tenant_id succeeds here.
spring.flyway.target=3
# Only the new write shape succeeds after this stage.Verification boundary
BootFlywayStartupTest.bootAppliesEachStageBeforeTheApplicationReadsRows. The excerpt is shortened; the source kit contains the checked fixture.
Costs and limits
Two contexts run sequentially on H2. There is no simultaneous old/new process pair, real user traffic or target-engine DDL measurement.
Common Mistakes
- Do not deploy the NOT NULL phase while an old writer still runs.
- Do not label a sequential test a mixed-version concurrency test.
- Do not equate a non-null legacy value with verified tenant ownership.
Read next
Spring Boot Flyway startup: apply versioned SQL before querying a receipt, Flyway expand and contract: show exactly when an old writer breaks, Spring schema rollout tests: check old and new writers at every phase, Spring JdbcTemplate tenant predicates: put ownership in the SQL query.
