Setting Up Liquibase: Where Manual Migrations Break the Release
Setting up Liquibase begins with a simple fact: as long as the DB schema is rolled out by hand — with a script over ssh, a file from a ticket, a command in the console — schema drift between the development environment, the test environment, and production appears unnoticed.
Edits made "on the fly" directly on a stage do not make it into the repository, and the next deployment applies them on top of someone else's version. Manual DB migrations look manageable while there are two environments and three people.
The consequence shows up at release: a failure during deployment because the column has already been created or the type does not match, while the application expects a different schema.
Then comes manual release rollback, dump comparison, searching for a forgotten change in logs and chat. The deployment window stretches, and confidence that the next migration will go just as smoothly does not appear.
Liquibase turns the schema into a versioned artifact: the changelog lives next to the code, each migration gets an identifier and a checksum, and the order of application and the fact of rollout are recorded in a service table.
A repeated run does not apply a change twice, a backdated edit is caught by checksum, and environments converge to a single schema from a single source — regardless of whether it is development or production.
Below we break down how this is covered: changelog structure, contexts and labels for different environments, rollback of changes, and embedding migrations into the deployment pipeline.
What Migration Automation Gives: Effect by Delivery Stage
The effect of migration automation is assessed not by general impression, but by measurable points at each delivery stage.
We track four marks and compare them before and after implementation — this shows exactly what moving schema changes from manual actions to Liquibase provides.
Environment Reproducibility
Schema versioning makes the set of migrations the only source of truth: development, the test stage, and the production environment are assembled from a single directory, not from edits made by hand on each of them.
The check is simple — deploy an environment from scratch and compare its structure with a stage where changes were applied gradually: there should be no discrepancies.
Change Deployment Time
Migrations run in one pass together with the application release, without a separate window for manual scripts and without depending on whether the on-call engineer remembers the required sequence.
Deployment time stops growing with the number of edits — it is determined by the volume of changes, not by the number of steps around them.
Downtime During Updates
Steps are lined up according to the "expand — fill — contract" pattern: first compatible objects, then data transfer, then removal of the old.
The application works on both schema versions at the same time, so downtime during updates either disappears or is reduced to something imperceptible to users.
Share of Schema Errors and the Eliminated Class of Failures
The state is recorded by the journal of applied migrations, a repeated run is safe, and divergence between stages is visible before release.
This eliminates a whole class of failures: a forgotten script on one environment, a conflict between two developers' edits, a release rollback without a plan for the structure.
Comparison of Migration Modes: Schema, Data, Rollback
The mode of applying changes is chosen by the nature of the task, not by habit: adding a column or index is one story; migrating and normalizing values is a completely different one.
The difference is visible in rollback: schema changes in most databases are not automatically undone, while data operations go away together with the transaction.
The second factor is who initiates the rollout. While an engineer applies changes manually, order rests on agreements; in a pipeline, it is fixed by a tool such as Liquibase, and then it is critical what exactly is in the changesets and how their integrity is verified.
| Mode | When it fits | Limitations |
|---|---|---|
| Schema only | Stable data: new tables, indexes, columns without value migration | Does not cover data migrations — backfills and normalization are prepared separately |
| Schema together with data | New columns with population, one-time backfills, renames | Long operations hold locks, data rollback works only inside a transaction |
| Prepared changesets | Repeatable releases, multiple environments, reproducibility | Review and integrity control are needed, otherwise divergence will be applied blindly |
| Manual rollout | Emergency edits and incident investigation | No history or repeatability, rollback rests entirely on the engineer |
We fix the mode before release: it determines what goes into the changesets and what rollback we can offer during an incident.
Setting Up Liquibase in the Build and Delivery Pipeline
Setting up Liquibase in the delivery pipeline starts from the actual state of the schema, not from documentation: discrepancies between environments usually surface during deployment. Below is the sequence of work that we go through together with the customer's team.
- Inventory. We compare the schemas of the development, pre-release, and production environments, collect objects living outside the migration system, and the discrepancies accumulated through manual edits.
- Changelog structure. We split changes into files by release, define a unified identifier format, and connect the root master file — the history of edits can be read without archaeology.
- Change description. Each change is documented together with its reverse operation: apply and rollback live in the same set, so a release rollback does not turn into manual work under load.
- Launch parameters. We configure contexts and labels by environment: service changes do not go to the production environment, and heavy operations run in a separate stream.
- Migration verification. We run changes on the pre-release environment against a copy of production data — we look at execution time, locks, query plan, and rollback effort.
- Journal of applied versions. The control table becomes the only source of truth about the database state: it shows what was applied and when, and recovery after a failure starts from it.
- Handover of the regulations. We give the team rules for adding changes, automated checking in the pipeline, and the procedure for conflicts — migrations stop being the domain of a single engineer.
What Remains in the Repository: Files, Schemas, Regulations
The project output is not a set of one-time edits in the database, but a reproducible migration environment: a clean stage comes up with a single command, and no discrepancies remain between environments.
We hand over not only code, but also artifacts that the customer's team can use to continue working without us.
- Change files — ordered descriptions of migrations with reverse operations and separation into logical sets; it is clear which change belongs to which task and how to remove it.
- Environment schema — which environments exist, how they differ in permissions and data, where application happens automatically during build, and where only manually with confirmation.
- Deployment regulations — the sequence of steps, the application window, the person responsible for launching, the procedure for an incompatible change, and stop rules.
- Database access policies — a separate account for migrations with the minimum required permissions, read and write roles, prohibition of manual structure edits bypassing the repository.
- Application procedure across environments — from the test stage to production, with verification on a data copy and synchronization of change numbers.
- Instructions for the on-call shift — what to look at in the journal, how to diagnose a stuck migration, how to roll back, and whom to involve.
- Documentation handover — data model description, change map, responsible persons, and escalation procedure; acceptance is based on a checklist, not memory.
Case: Migrations Under Automated Control
The customer was developing a service with three environments: development, a pre-production stage, and production. Schema edits were applied manually — an engineer connected to the database, executed a file with changes, and repeated the same on the next stage.
Discrepancies between environments were found by eye, table structures were compared before release, and the order of applying files was kept in their head and in chat.
Changes were moved to Liquibase: each step is described as a separate set in the repository, next to the code, and is applied automatically during deployment.
The schema state is now determined by the list of applied sets, not by a specific engineer's memory — exactly what has already passed development goes to any stage.
Metrics Before and After
Preparing the database structure before release: it was 40–60 minutes of manual work tied to one person; it became 6–8 minutes of an automated run.
Schema-related requests per quarter: seven before the migration and one after — and that one was caught on the pre-production stage, not in production.
A whole class of failures is gone: reapplying the same change, the wrong file order, and a forgotten stage.
The application history is stored in the database itself, so you can return to the previous schema state in a targeted way, rather than restoring the entire environment from a nightly copy.
What to Do If the Database Is Already Deployed and There Are Discrepancies?
A deployed database is brought into managed mode not from the first migration, but from a fixed reference point.
The first step is inventorying changes: we capture the actual schema (DDL dump or system catalog), compare it with what the changelog describes, and divide discrepancies into three groups — applied manually, missing, and diverged by field type or length. Until this picture is assembled, any migration is a lottery with data.
Next is baseline: with the changelog-sync command, Liquibase marks existing changeSets as executed without running them, and a tag on the current schema state becomes the rollback point.
After that, the database is brought to the target state according to the changelog version, and all further changes go only through migrations — no one touches production by hand anymore.
A safe transition is built on previewing: first a run on a copy with a real data volume, then update-sql — to see what exactly will go into the database, and only then application.
Each changeSet runs in its own transaction where the DBMS supports it, a lock on the migration journal prevents two releases from starting in parallel, and changes with heavy locks are moved to an agreed window.
If the schema was edited outside migrations, this will be caught by the checksum of records: validate and status stop the build before deployment, not after it.
One-time discrepancies thus turn into a fixed baseline, rather than permanent manual synchronization of two schema versions.
Technical Doubts Before Implementing Migrations
Some doubts are resolved by the migration mechanics itself — the journal of applied changeSets and checksum verification. The rest is ensured by the regulations and how the changelog is organized. We answer the questions most often raised at the evaluation stage.
Developers edit the database outside migrations — will this break the process?
A change not entered into the changelog is not seen by the journal: on the next run, checksum verification will show a discrepancy, and the migration will stop.
Therefore, we close direct access to stages, and urgent edits are documented as a separate changeSet — it enters the history and is reproduced on the other environments.
Several teams migrate the schema at the same time — will there be a conflict?
Each module maintains its own changelog and connects to the common one through the root file, so teams do not intersect in each other's changeSets. A service lock on the journal removes the race if migrations are launched in parallel.
How do you roll back a failed migration?
For a changeSet with a paired rollback, rollback is performed with a single command. For irreversible operations — deleting or renaming a column — we prepare a compensating migration in advance and test it on a copy of the production database.
Who and how launches changes in the production environment?
Migrations are applied by the pipeline after changeSet review, not by a person by hand. Direct access to the production database remains with the on-call engineer and is logged — we describe the access regulations in the documentation.
The schemas on stages have diverged — what to do?
The single source is the changelog, and we describe environment differences with contexts and labels: a subset of migrations is applied on a stage, and the schema is brought to the required version without manual scripts.
Let's Discuss the Task: What Is Needed to Start Migrations
Starting work requires nothing from the customer except access to what they already use. We do not ask you to create new accounts or rewrite the schema — at the first step, it is enough to understand how changes reach the database today and compare this with the target process.
What we need from you at the input:
- List of databases and stages: development, test, pre-production, production — and where migrations are currently applied manually.
- Repository with current SQL scripts or schema description — from it we assemble the baseline and see discrepancies between environments.
- Access to the build system and the migration server: a service user with rights to change the schema, but without rights to production data.
- Regulations: maintenance windows, rollback requirements, who confirms application in production.
- The person responsible for the schema on the product side — the one who approves edits before deployment.
Then the procedure is: we discuss the task and the current process, estimate the scope — the number of databases, the size of the baseline, the complexity of conflicting edits.
Based on the assessment, we prepare a plan for moving changes under Liquibase: which environment we start with, how we synchronize already applied scripts, and what rollback looks like at each step.
We agree on the plan together with timelines and the point of no return — the moment after which schema edits go only through migrations.







