Choosing Between Hibernate SchemaUpdate and Liquibase Migrations for Rollback-Safe Production Deployments
0 reputation · 26 Sept 2023, 21:45 UTC
0 reputation · 26 Sept 2023, 21:45 UTC
A Grails 6 application must support production schema changes that can be rolled back reliably within a defined maintenance window. The team currently uses dbCreate: "update" in development but recognizes it provides no rollback mechanism for failed deployments.
The grails-database-migration plugin (Liquibase) offers explicit rollback via dbmRollback, yet only changesets using reversible Liquibase refactorings (e.g., createTable, addColumn) roll back automatically. Destructive operations—column drops, type narrowing, constraint removals—require manually authored rollback SQL, which dbmGormDiff cannot generate. Running both dbCreate: "update" and the migration plugin concurrently is documented as unsafe because SchemaUpdate applies DDL outside Liquibase's DATABASECHANGELOG, causing drift that breaks rollback integrity.
Test environments often use dbCreate: "create-drop" with H2, which does not exercise Liquibase rollback paths. Multi-tenancy schema-per-tenant features in GORM 8 add further ambiguity: the plugin's rollback behavior for tenant-specific schemas is undocumented and only experimentally verified per tenant, not globally.
Given these constraints, which approach provides a verifiable rollback path for a changeset containing a dropColumn operation in a multi-tenant schema? Should the team accept manual rollback authoring for every destructive change, or is there a documented pattern that preserves automated rollback without disabling dbCreate in CI?
For a production Grails 6 application that must be able to roll back a dropColumn change in a schema‑per‑tenant setup, the only verifiable path is to use the grails‑database‑migration (Liquibase) plugin exclusively, disable Hibernate’s dbCreate (set to none or validate), and author a manual <rollback> section that re‑adds the column. Automatic rollback cannot be achieved for destructive operations, and running SchemaUpdate alongside Liquibase breaks rollback integrity.
dropColumn cannot be undone by Hibernate alone.dropColumn is not reversible, so a manual <rollback> containing the corresponding addColumn SQL is required for dbmRollback to succeed.dbCreate: "update" together with dbmUpdate is unsafe because SchemaUpdate executes DDL outside Liquibase’s DATABASECHANGELOG, causing drift that invalidates Liquibase‑based rollback.Because the only way to guarantee a deterministic inverse of a destructive column drop is to store the exact inverse SQL yourself, the migration framework must be the sole source of truth for schema changes. Disabling dbCreate prevents Hibernate from applying out‑of‑band DDL that would otherwise create drift and break the Liquibase changelog.
dbCreate: "none" (or validate if you want startup validation) in application.yml for all environments.<changeSet id="20261013-drop-col" author="dev">
<dropColumn tableName="my_table" columnName="old_col"/>
<rollback>
<addColumn tableName="my_table">
<column name="old_col" type="varchar(255)"/>
</addColumn>
</rollback>
</changeSet>
grails dbmUpdate to apply the change to each tenant datasource (or iterate over your tenant list).grails dbmRollback <count> (or target the specific changeSet) against each tenant and confirm the column is restored.dbCreate: "validate" if you want Hibernate to check for drift without applying changes; otherwise leave it as none.Missing diagnostic detail: Can the team safely set dbCreate: "validate" in their CI pipeline to let Hibernate detect schema drift without applying DDL? If yes, they can retain validation while still relying on Liquibase for all actual changes; if not, they must disable dbCreate entirely.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.