Liquibase and Zero-Downtime Deployments: Managing Schema Evolution Phases
0 reputation · 18 Oct 2021, 02:43 UTC
0 reputation · 18 Oct 2021, 02:43 UTC
Implementing a zero-downtime migration strategy requires coordinating database schema changes with application code deployments. To avoid breaking the running application, schema evolution must be split into additive and destructive phases.
The goal is to ensure that the database supports both the current version of the application and the next version simultaneously during the rollout. This typically involves adding new columns or tables before updating the application logic, and removing deprecated elements only after the new version is fully stable.
When using Liquibase to automate these transitions, it is unclear how to best structure the changelog to prevent destructive operations from executing prematurely in a CI/CD pipeline without manually editing the changelog for every environment.
35775 reputation · 18 Oct 2021, 13:08 UTC
Decouple additive and destructive schema work with Liquibase contexts and labels, and gate the destructive run on the CI/CD pipeline after application health checks. Liquibase has no built-in hook to wait for an application health check; the pipeline must control timing.
context="additive" runs only when --contexts=additive is passed.label="phase:cleanup", and be filtered with --labels.<changeSet id="1" author="team" context="additive">
<addColumn tableName="orders">...</addColumn>
</changeSet>
<changeSet id="2" author="team" context="destructive" label="phase:cleanup">
<dropColumn tableName="orders" columnName="old_flag" />
</changeSet>
Additive changes run on every deploy. Destructive changes are defined but remain pending.liquibase update --contexts=additive
Run this in the same pipeline stage as the new application version. The database now supports both old and new app versions.liquibase update --contexts=destructive
This executes only the cleanup changesets. Context and label matching is case-sensitive.Before enabling destructive contexts in production, validate the split on a scratch database:
liquibase update-sql --contexts=additive
Inspect the generated SQL to confirm destructive statements are absent. After the health-check gate, compare DATABASECHANGELOG entries before and after the destructive run to confirm only the intended cleanup changesets executed.
It is likely that contexts and labels are sufficient to prevent premature destructive execution without editing changelogs per environment. The confirmed limitation is that Liquibase will not wait for health checks itself; the orchestrator must enforce the two-phase run.
One diagnostic detail that changes the recommendation: are you running rolling updates where old application instances remain live during the rollout? If yes, destructive cleanup must wait until the last old instance is terminated, not just until the new version reports healthy.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.