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:createadd 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: applechangelog.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: rootrootupdate 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 contextFilters attached
liquibase updateLiquibase 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: rootrootupdate 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"