How can I ensure Liquibase rollbacks are truly safe and testable in real-world deployments?

Hi everyone,

I’m currently working on a Liquibase-based CI/CD pipeline, and I have a question regarding rollback safety and best practices in real production environments.

Imagine the following situation:

  • A changeset creates a table and inserts a row.
  • A rollback is defined (e.g., DELETE and DROP TABLE).
  • The update runs successfully.
  • But when executing the rollback, it fails due to a logic or constraint error.

At this point, part of the change is already applied, and the rollback can’t clean it up automatically.

My questions for the community:

  1. How do you normally deal with this in real life?
  • Do teams manually clean up the changes?
  • Are there structured rollback playbooks?
  1. Is there any way to validate that a rollback actually works before applying the change in production?
  • I already use future-rollback-sql, but it only checks for syntax and presence—not actual execution success.
  1. Have you found ways to automatically test update + rollback together safely as part of a pipeline?
  • I’ve tried wrapping Liquibase in a custom Java tool that uses conn.setAutoCommit(false) to simulate atomicity, but I know this isn’t Liquibase’s default behavior.
  1. Is there a better pattern for testing rollback validity when the changeset contains both DDL and DML?

My goal is to make sure that if a rollback is defined, it truly works, and if it doesn’t, the changeset never gets applied in the first place.

Any guidance, real-world strategies, or patterns you’ve found helpful would be greatly appreciated!

Thanks in advance

Hey @OmarNoah! Answers & recommendations below…

  1. How do you normally deal with this in real life?

If a database ends up in the state you describe, manual intervention is necessary. You’ll need to clean up the partially deployed or rolled back change. You might also need to update the DATABASECHANGELOG table that tracks changeset execution to remove the entry for the changeset that didn’t rollback cleanly.

  1. Is there any way to validate that a rollback actually works before applying the change in production?

There are a couple of ways to do this and what’s right for you depends heavily on what’s available in your pipeline. A lot of users will test update and rollback in a pre-prod database that is frequently refreshed from production. Other users will use containerized databases in their workflows to test the update and rollback they are introducing. We recommend that update and rollback not be tested in prod because…well…nothing should really be tested in prod. If you have replicated databases in prod you could conceivably work out a blue/green deployment to test everything if you are able to remove a database from the replication cluster or temporarily pause replication to protect your data through isolation.

  1. Have you found ways to automatically test update + rollback together safely as part of a pipeline?

There is the update-testing-rollback command that performs an update, performs the rollback for that update, and then performs the update again to make sure that the rollback sufficiently undoes the changes. I’ve also seen users build a CI workflow with individual commands to accomplish a more thorough version of this: taking a pre-update snapshot; run the update; run the rollback; compare the current state of the database to the snapshot taken in step 1. If there are no differences detected, you can be reasonably comfortable that the rollback did what it was supposed to.

Take a look at the Liquibase Rollback Workflow docs for more information. Good luck!