Each database query in ChangeLog
file is subdivided into individual ChangeSet
files. liquibase update
command runs the ChangeLog
file, by default, executes each individual ChangeSet
mentioned. Liquibase
provides a context
attribute that allows control and filters the execution of ChangeSet
via context
attribute.
Difference between context and labels is context allows complex filtering logic such as @ ! or and , () at compile time in ChangeSet attribute of ChangeLog file, whereas labels provides the same filtering logic at run time in CLI.
context syntax in changelog file is as below
-- changeset wesome:1692430545055-1 contextFilter:create
add context
in the update command
liquibase update --contexts="create"
Let's consider an example, assume a new table needs to be created and a record needs to be inserted in the development
environment, but in production
, only the table is required but without the data. both the query is mentioned individually ChangeSet
with create and insert contextFilter
respectively in a ChangeLog
file as below.
changelog.mysql.sql
-- liquibase formatted sql
-- changeset wesome:1692430545055-1 contextFilter:create
CREATE TABLE appledb.apple (apple_id BIGINT NOT NULL, apple_name VARCHAR(255) NULL);
-- changeset wesome:1692430545055-2 contextFilter:insert
INSERT INTO appledb.apple (apple_id, apple_name) VALUES (1, 'Macintosh');
changelog.mysql.xml
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet author="wesome (generated)" id="1692428530882-1" contextFilter="create">
<createTable catalogName="appledb" tableName="apple">
<column name="apple_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="apple_name" type="VARCHAR(255)"/>
</createTable>
</changeSet>
<changeSet author="wesome (generated)" id="1692428530882-2" contextFilter="insert">
<insert catalogName="appledb" tableName="apple">
<column name="apple_id" valueNumeric="1"/>
<column name="apple_name" value="Macintosh"/>
</insert>
</changeSet>
</databaseChangeLog>
changelog.mysql.yaml
databaseChangeLog:
- changeSet:
id: 1692431025481-1
author: wesome (generated)
contextFilter: create
changes:
- createTable:
catalogName: appledb
columns:
- column:
constraints:
nullable: false
name: apple_id
type: BIGINT
- column:
name: apple_name
type: VARCHAR(255)
tableName: apple
- changeSet:
id: 1692431025481-2
author: wesome (generated)
contextFilter: insert
changes:
- insert:
catalogName: appledb
columns:
- column:
name: apple_id
valueNumeric: 1
- column:
name: apple_name
value: Macintosh
tableName: apple
changelog.mysql.json
{
"databaseChangeLog": [
{
"changeSet": {
"id": "1692430982187-1",
"author": "wesome (generated)",
"contextFilter": "create",
"changes": [
{
"createTable": {
"catalogName": "appledb",
"columns": [
{
"column": {
"constraints": {
"nullable": false
},
"name": "apple_id",
"type": "BIGINT"
}
},
{
"column": {
"name": "apple_name",
"type": "VARCHAR(255)"
}
}
],
"tableName": "apple"
}
}
]
}
},
{
"changeSet": {
"id": "1692430982187-2",
"author": "wesome (generated)",
"contextFilter": "insert",
"changes": [
{
"insert": {
"catalogName": "appledb",
"columns": [
{
"column": {
"name": "apple_id",
"valueNumeric": 1
}
}
],
"tableName": "apple"
}
}
]
}
}
]
}
liquibase.properties (update ChangeLog
File format with SQL, XML, YAML, JSON as per changelog.mysql.<format>)
changeLogFile=changelog.mysql.sql
liquibase.command.url:jdbc:mysql://localhost:3306/AppleDb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
liquibase.command.username: root
liquibase.command.password: rootroot
update command with create context
will only create the table
liquibase update --contexts="create"
update command with insert context
will only insert into the table assuming the table exists or else will throw an error
liquibase update --contexts="update"
update command with both comma-separated contexts will execute both the ChangeSet
liquibase update --contexts="create, insert"
update command without any context
will
By default, if no context
is provided in the update command, it will run all ChangeSet
even if they have contextFilter
s attached
liquibase update
Liquibase older than 4.16.0, was using syntax as context="development" in ChangeSet, which is updated to contextFilter="development" in newer versions, although, context is still supported.
context
has many use cases, but the most common is to specify environments in which ChangeSet
should execute. For example, certain ChangeSet
should only be run in production
or development
environments. Contexts are very useful if you need to specify complex filtering logic while writing ChangeSet
, rather than specifying at runtime.
Context filtering
After the release of version 3.2.0+, Liquibase
allows to specify CLI context
with AND
, OR
, !
, and
, ()
in the changesets.
contextFilter="!development"
will execute ChangeSet
with all contexts except development
contextFilter="v1.0 or development"
will execute the ChangeSet
if the update command context
is mentioned as v1.0 or development
contextFilter="!development and !production"
will execute the ChangeSet
if, in the update command, the context
is not development
and production
Context separated with "," is equivalent to an OR operation but has the highest precedence
contextFilter="development, production" is the same as contextFilter="development OR production"
will execute the ChangeSet
if, in the update command, the context
is either development
or production
contextFilter="development, test and production" is the same as contextFilter="(development) OR (test and production)"
will execute the ChangeSet
if, in the update command, the context
is either development
or test and production
Prior to Liquibase
version 4.23, if the context
is not mentioned in the CLI update command, all the ChangeSet
will be executed regardless of contextFilter
mentioned in ChangeSet
, but in versions 4.23+, a contextFilter
mentioned with @ will only run if the context
is mentioned in CLI
ContextFilter in databaseChangeLog
A ChangeLog
file can include multiple ChangeLog
files, assuming the changes are segregated as per creation and insertion, Liquibase
allows to specify contextFilter
in the parent databaseChangeLog attribute which will apply the contextFilter
in all the ChangeSet
mentioned in the file let's understand this with an example
ChangeSet
for creating apple
table and vendor
are defined in changelog.mysql.create.xml
and ChangeSet
for insertion data in apple
table and the vendor
is defined in changelog.mysql.insert.xml
.
add attribute contextFilter="create"
and contextFilter="insert"
into respective ChangeLog
files as below.
changelog.mysql.create.xml
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog contextFilter="create" xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd" >
<changeSet author="wesome (generated)" id="1692436784799-1">
<createTable catalogName="appledb" tableName="apple">
<column name="apple_id" type="BIGINT">
<constraints nullable="false" primaryKey="true"/>
</column>
<column name="apple_name" type="VARCHAR(255)"/>
</createTable>
</changeSet>
<changeSet author="wesome (generated)" id="1692436784799-2">
<createTable catalogName="appledb" tableName="vendor">
<column name="vendor_id" type="BIGINT">
<constraints nullable="false" primaryKey="true"/>
</column>
<column name="vendor_name" type="VARCHAR(20)"/>
<column name="active" type="CHAR(1)"/>
<column name="apple_id" type="INT"/>
</createTable>
</changeSet>
</databaseChangeLog>
changelog.mysql.insert.xml
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog contextFilter="insert" xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet author="wesome (generated)" id="1692436784799-3">
<insert catalogName="appledb" tableName="apple">
<column name="apple_id" valueNumeric="1"/>
<column name="apple_name" value="Macintosh"/>
</insert>
</changeSet>
<changeSet author="wesome (generated)" id="1692436784799-4">
<insert catalogName="appledb" tableName="vendor">
<column name="vendor_id" valueNumeric="1"/>
<column name="vendor_name" value="Macintosh_Vendor"/>
<column name="active" value="Y"/>
<column name="apple_id" valueNumeric="1"/>
</insert>
</changeSet>
</databaseChangeLog>
include both changelog.mysql.create.xml
and changelog.mysql.insert.xml
into parent changelog.mysql.xml
file as below
changelog.mysql.xml
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<include file="changelog.mysql.create.xml"/>
<include file="changelog.mysql.insert.xml"/>
</databaseChangeLog>
liquibase.properties
changeLogFile=changelog.mysql.xml
liquibase.command.url:jdbc:mysql://localhost:3306/AppleDb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
liquibase.command.username: root
liquibase.command.password: rootroot
update command with context="create"
will only execute the ChangeSet
of changelog.mysql.create.xml
and only create tables in the database
liquibase update --contexts="create"
update command with context="insert" will only execute the ChangeSet
of changelog.mysql.insert.xml
and only insert into the table assuming the table exists or else will throw an error
liquibase update --contexts="insert"
ContextFilter in include and includeAll tag
A ChangeLog
file can include another ChangeLog
file with the help of the include
command or include all the ChangeLog
files in a directory with the help of includeAll
tag
ChangeSet
for creating the apple
table and vendor
are defined in changelog.mysql.create.xml
and ChangeSet
for insertion data in apple
table and the vendor
is defined in changelog.mysql.insert.xml
.
changelog.mysql.create.xml
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd" >
<changeSet author="wesome (generated)" id="1692436784799-1">
<createTable catalogName="appledb" tableName="apple">
<column name="apple_id" type="BIGINT">
<constraints nullable="false" primaryKey="true"/>
</column>
<column name="apple_name" type="VARCHAR(255)"/>
</createTable>
</changeSet>
<changeSet author="wesome (generated)" id="1692436784799-2">
<createTable catalogName="appledb" tableName="vendor">
<column name="vendor_id" type="BIGINT">
<constraints nullable="false" primaryKey="true"/>
</column>
<column name="vendor_name" type="VARCHAR(20)"/>
<column name="active" type="CHAR(1)"/>
<column name="apple_id" type="INT"/>
</createTable>
</changeSet>
</databaseChangeLog>
changelog.mysql.insert.xml
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet author="wesome (generated)" id="1692436784799-3">
<insert catalogName="appledb" tableName="apple">
<column name="apple_id" valueNumeric="1"/>
<column name="apple_name" value="Macintosh"/>
</insert>
</changeSet>
<changeSet author="wesome (generated)" id="1692436784799-4">
<insert catalogName="appledb" tableName="vendor">
<column name="vendor_id" valueNumeric="1"/>
<column name="vendor_name" value="Macintosh_Vendor"/>
<column name="active" value="Y"/>
<column name="apple_id" valueNumeric="1"/>
</insert>
</changeSet>
</databaseChangeLog>
add attribute contextFilter="create"
and contextFilter="insert"
into respective include commands in parent changelog.mysql.xml
file as below.
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<include contextFilter="create" file="changelog.mysql.create.xml"/>
<include contextFilter="insert" file="changelog.mysql.insert.xml"/>
</databaseChangeLog>
update command with context="create"
will only execute the ChangeSet
of changelog.mysql.create.xml
and only create tables in the database
liquibase update --contexts="create"
update command with context="insert"
will only execute the ChangeSet
of changelog.mysql.insert.xml
and only insert into the table assuming the table exists or else will throw an error
liquibase update --contexts="insert"
Context names are case-insensitive strings
context
defined in ChangeSet
, databaseChangeLog, include or includeAll attributes are case insensitive, for example below context
<changeSet changelog="create" author="wesome (generated)" id="1692436784799-1">
will run in both cases
liquibase update --contexts="insert" or liquibase update --contexts="INSERT"