Liquibase: Changelogs & Changesets
|
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. |
Changeset Identity
A changeset is uniquely identified by the triple id + author + the changelog file it is declared in, per
What is a Changeset?. Liquibase tracks this triple
in DATABASECHANGELOG (Liquibase: Tracking &
Locking) — change any part of it and Liquibase treats the changeset as new and runs it again, even if the SQL
inside is identical to one already applied. id does not need to be numeric or sequential; a descriptive string
(add-email-column) works just as well and is often clearer in review.
One Change Type per Changeset
Liquibase recommends keeping exactly one change type (createTable, addColumn, addForeignKeyConstraint, and
so on) per changeset. This matters most for rollback: Liquibase’s auto-generated inverse
(Liquibase: Rollback) is derived per change type, and a
changeset mixing several change types either can’t be auto-rolled-back at all or rolls back in a way that’s
harder to reason about. It also keeps the audit trail’s granularity meaningful — one row in
DATABASECHANGELOG per logical change.
Splitting Large Changelogs: include and includeAll
A single master changelog can pull in others, so a large schema’s history doesn’t live in one file:
databaseChangeLog:
- include:
file: db/changelog/001-initial-schema.yaml
- include:
file: db/changelog/002-add-email-column.yaml
- includeAll:
path: db/changelog/releases/
include names one file explicitly; includeAll pulls in every changelog file under a directory, in
lexicographic filename order — the common convention is to prefix each file with a date or an incrementing
number so that ordering is obvious from the filename alone. Splitting by feature, by release, or by team keeps
merge conflicts down when several people add changesets concurrently.
A Two-Changeset Example: Ordering Across Files
Changeset 1 (001-create-person-table.yaml) creates a table:
databaseChangeLog:
- changeSet:
id: create-person-table
author: alberto
changes:
- createTable:
tableName: person
columns:
- column: { name: id, type: bigint, autoIncrement: true, constraints: { primaryKey: true } }
- column: { name: name, type: varchar(255), constraints: { nullable: false } }
Changeset 2 (002-add-person-email.yaml), included after it, adds a column:
databaseChangeLog:
- changeSet:
id: add-person-email
author: alberto
changes:
- addColumn:
tableName: person
columns:
- column: { name: email, type: varchar(255) }
Because both files are pulled in via includeAll from a directory where 001- sorts before 002-, Liquibase
applies create-person-table before add-person-email on a fresh database — but on a database that already has
create-person-table recorded as applied, only add-person-email runs.
Generating a Changelog from an Existing Database
For a database that predates Liquibase, generateChangeLog inspects the live schema and writes out a changelog
that would recreate it — a starting point for bringing an existing database under Liquibase management:
liquibase generateChangeLog --changelog-file=baseline.yaml
diff and diffChangeLog instead compare two databases (or a database against a changelog) and produce only the
changesets needed to reconcile the difference — useful for catching drift, or for generating the changesets for
a change that was prototyped directly against a database:
liquibase diffChangeLog --reference-url=jdbc:postgresql://localhost/reference --changelog-file=diff.yaml
Both commands produce a starting draft, not a finished changelog — review the output before committing it, since generated changesets don’t include the semantic intent (why the schema looks the way it does) a hand-written one would.