Using Liquibase Contexts to Apply Environment‑Specific Changesets
Learn how Liquibase contexts let you tag changesets and run only those matching a supplied --contexts argument, with a concrete XML example, verification steps, and common pitfalls.
23 Jun 2026, 17:15 UTC

Why Use Liquibase Contexts
Liquibase contexts let you tag individual changesets with one or more labels. When you run liquibase update you supply a --contexts argument; only changesets whose context list matches (using OR semantics) are executed. This lets you keep a single changelog file while applying different schema changes for dev, test, or prod environments.
Worked Example (XML)
The following changelog defines two changesets, each tied to a specific context:
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.xsd">
<changeSet id="dev-feature-table" author="me" context="dev">
<createTable tableName="dev_feature">
<column name="id" type="int">
<constraints primaryKey="true"/>
</column>
</createTable>
</changeSet>
<changeSet id="prod-feature-table" author="me" context="prod">
<createTable tableName="prod_feature">
<column name="id" type="int">
<constraints primaryKey="true"/>
</column>
</createTable>
</changeSet>
</databaseChangeLog>
Running the update with a dev context:
liquibase --changeLogFile=changelog.xml \ --url=jdbc:postgresql://localhost:5432/mydb \ --username=liquibase_user \ --password=**** \ update --contexts=devOnly the
dev-feature-tablechangeset is executed; the prod changeset is recorded asEXECUTED=0and no SQL is sent to the database.How Context Evaluation Works
For each changeset Liquibase:
- Reads the
<context>element (or attribute).- Splits the supplied
--contextsvalue on commas.- Applies OR logic: if any of the changeset’s contexts appears in the runtime list, the changeset runs.
- If there is no match, Liquibase inserts a row into
DATABASECHANGELOGwithEXECUTED=0and skips the SQL.Because the decision is made before SQL generation, the skipped changeset never touches the target database.
Verification Steps
- Start with an empty database (or a known clean state).
- Execute the command shown above with
--contexts=dev.- Check the log: you should see output like "Executing UPDATE: dev-feature-table" and no mention of the prod changeset.
- Run a diagnostic query:
SELECT id, author, context, executed FROM DATABASECHANGELOG ORDER BY id;Expected result:
| id | author | context | executed |
|---|---|---|---|
| dev-feature-table | me | dev | 1 |
| prod-feature-table | me | prod | 0 |
Additionally, you can preview the SQL that would be run:
liquibase updateSQL --contexts=dev
The generated SQL should contain only the CREATE TABLE dev_feature statement.
Limits and Common Mistakes
- Case sensitivity: Context strings are compared exactly as written.
--contexts=Devwill not match a changeset withcontext="dev". - Mixing contexts and labels: Liquibase also supports the
<label>element. If you use both, the runtime--contextsargument does not affect label evaluation, which can lead to unexpected skips. runOnChange=true: A changeset marked with this attribute will not re‑run after being skipped due to a context mismatch, because Liquibase treats it as already executed (EXECUTED=0) and does not recompute its checksum on subsequent runs.- Checksum impact: Adding, removing, or changing a context alters the changeset’s XML, which changes its checksum. On an existing database this can trigger a validation error unless you re‑baseline or manually update the checksum in
DATABASECHANGELOG. - Concurrent instances: If two Liquibase processes run against the same schema with different
--contextsvalues, one may apply a changeset while the other skips it, causing divergent schema states. Ensure all instances share the same context list for a given run.
Practical Checks After a Change
After you modify a context (e.g., add context="dev,test" to a changeset), run:
liquibase update --contexts=devThen verify:
- The changeset appears as
EXECUTED=1inDATABASECHANGELOG.- The corresponding database object exists.
- Running
liquibase validatereports no checksum mismatches (or you have manually updated the checksum).If validation fails, you can either:
- Run
liquibase changelogSyncto mark the changeset as executed in the database, or - Manually set the
MD5SUMcolumn to the new checksum value shown in the changelog.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.