Liquibase: Rollback
|
This section documents schema/database evolution using version-controlled migration tools — Liquibase (relational/SQL), Mongock (MongoDB, Java-native) and Flamingock (Mongock’s successor, generalized to any external system) — as described by each tool’s own official documentation: liquibase.org and docs.liquibase.com for Liquibase, docs.mongock.io for Mongock, and docs.flamingock.io for Flamingock — which are the references these pages are written and verified against. This content was generated with the assistance of AI and should be verified against those official docs before being relied on in production. Mongock is now maintained under the Flamingock GitHub organization (github.com/flamingock/mongock), and Flamingock is positioned as its successor — see Coming from Mongock. Readers starting a new project should default to Flamingock unless they have a specific reason to stay on Mongock. This section’s bibliography lists the reference material consulted while preparing these pages. |
Automatic Rollback
For change types with an obvious, well-defined inverse, Liquibase generates the rollback SQL automatically — createTable rolls back to dropTable, addColumn to dropColumn, createIndex to dropIndex, and so on. No
extra authoring is needed:
- changeSet:
id: create-person-table
author: alberto
changes:
- createTable:
tableName: person
columns:
- column: { name: id, type: bigint, autoIncrement: true, constraints: { primaryKey: true } }
Rolling this back (see Count or Date) issues DROP TABLE person without any explicit
<rollback> block, per
What is a Rollback?.
Custom Rollback for Change Types With No Inverse
Some change types have no well-defined automatic inverse: dropTable (the data is gone — there is nothing to
recreate it from), insert (which row should delete remove, if several look alike?), and raw sql blocks (the
tool cannot infer intent from arbitrary SQL text). For these, an explicit <rollback> block is required if the
changeset should be reversible at all — Create
custom rollback statements:
- changeSet:
id: drop-legacy-audit-table
author: alberto
changes:
- dropTable:
tableName: legacy_audit
rollback:
- createTable:
tableName: legacy_audit
columns:
- column: { name: id, type: bigint, constraints: { primaryKey: true } }
- column: { name: event, type: varchar(255) }
The rollback block recreates the table’s shape — but note this restores the schema, not the data that was
in it, since dropTable destroyed that. A changeset with no meaningful inverse at all (a one-way data backfill,
for instance) can declare rollback: [] or <rollback/> explicitly to document "not reversible" rather than
leaving Liquibase to fail when a rollback is attempted.
Rolling Back by Tag, Count or Date
Liquibase can roll back to a named tag, a fixed number of changesets, or a point in time:
liquibase tag release-1.4 # mark the current state
liquibase rollback release-1.4 # undo everything applied after that tag
liquibase rollback-count 3 # undo the last 3 changesets
liquibase rollback-to-date 2026-01-01 # undo everything applied after that date
liquibase rollback-one-changeset --changeset-id=drop-legacy-audit-table --changeset-author=alberto \
--changeset-path=db/changelog/legacy-cleanup.yaml # undo exactly one changeset, out of order
rollback-one-changeset is deliberately narrow — it targets a single changeset by its full identity rather than
an ordered range, and is meant for reversing a specific mistake rather than routine deployment rollback. Tagging
a known-good state before a release (liquibase tag) is what makes rollback <tag> a reliable way back to it.