Liquibase Attributes Contexts

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 contextFilters 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"

follow us on