Labels

Labels are tags that control whether commands like update run certain changesets. You add labels directly to changesets in your changelog and filter them at runtime using the --label-filter attribute in the CLI. You can specify a label name as any case-insensitive string. The label filter is a logical expression that you can use to specify one or more changeset labels.

Labels work best when the changeset author can simply enumerate or describe what a changeset is used for, such as a particular feature or version. There may be greater complexity at runtime to determine what label expression should be used to perform the deployment, but that control is left to the deployment manager or person executing the changesets. Labels are similar to Contexts, which you can to specify other tags, such as development environments.

In Liquibase Pro 4.23.1+, you can easily set labels in bulk from your command line with the set-labels command instead of specifying them manually in your changelog.

Uses

You can typically use labels to:

  • Manage and track your deployments.
  • Apply complex logic to filter the changesets eligible for deployment.
  • Mark changesets based on features and then selectively apply those features at the execution time instead of using version control branches.
  • Use different languages for marking changesets. For example, you can mark your changesets both with Spanish and English.
  • Assign ticket numbers to particular changesets to track and identify their purpose, such as JIRA ticket numbers

label-filter runtime syntax

In Liquibase 4.23.0+, you can specify a label using @ in addition to AND, OR, !, and parentheses in the changesets. The @ is used for labels only at run time and forces any specific labeled changeset to execute.

Example: If a changeset is labeled as lables=test, only this changeset will be forced to execute if at runtime we specify --label-filter=@test.

Note: If you have a changeset marked with a label that starts with @ and you run Liquibase without specifying the --label-filter attribute, the changeset will not be executed. If label filters (--label-filter=) are specified as @test at runtime as described in the example above, no changeset will be executed if there are not any labels titled test.

Label filters can be specified using @, AND, OR, !, and () (parentheses that are used for grouping). For example:

  • --labelFilter="@test"
  • --labelFilter="!v.0.1"
  • --labelFilter="v.1.0 and v.1.1"
  • --labelFilter="v.1.0 or v.1.1"
  • --labelFilter="!v.1.0 and !v.1.1"

Using "," to separate labels works like an OR operation (a comma is an alias for OR). For example:

  • --label-filter="v.1.0, v.1.1" is the same as --label-filter="v.1.0 OR v.1.1"
  • --label-filter="v.0.1, v.1.0 and v.1.1" is the same as --label-filter="(v.0.1) OR (v.1.0 and v.1.1)"

You can run the --label-filter attribute to determine which changesets in the changelog to evaluate based on its label. Learn more about the labelFilter logic at this blog post.

  • In your changelog, you can specify only a simple list of labels to apply to the changeset. For example, labels="v.0.1, v.1.0".
  • At runtime, you can specify a complex expression with the labels that you want to execute. For example, --labelFilter="!v.0.1" or --labelFilter="v.1.0 or (v.1.1 and v.1.2)".

Note: Prior to version 4.16.0, the CLI argument was --labels rather than --label-filter. In 4.16.0 and beyond, --labels is a supported alias for --label-filter.

Usage

It is best practice to enumerate your changesets or describe what a changeset is used for. An example of labels indicating the version or a specific feature can be "1.0" or "shopping_cart". In this case, labels will allow you to run changes with:

  • --label-filter=1.0 to deploy the 1.0 changesets or --label-filter=shopping_cart to deploy the changesets related to the shopping cart.
  • --label-filter="1.0 or (1.1 and shopping_cart)" to deploy the 1.0 changesets and only the 1.1 features related to the shopping cart.
  • --label-filter="1.0 or (1.1 and !shopping_cart)" to deploy the 1.0 changesets and the 1.1 features that are not related to the shopping cart.

You can see an example of running the update command with complex --label-filter statements:

liquibase --output-file=update.txt update --changelog-file=changelog.xml --label-filter="1.0 or (1.1 and !shopping_cart)"

If a changeset doesn't have a label, it will always run. If you make a deployment without specifying any labels in the label filter, all changesets will run.

Example: If you run the liquibase update --label-filter=1.0 command, it will deploy all changesets with the label 1.0 and all changesets without any label. If you run liquibase update, it will deploy all changesets, whether they have labels or not.

--liquibase formatted sql

--changeset your.name:1 labels:1.0,prod,shopping_cart
CREATE TABLE person (firstname VARCHAR(255) NULL);

--changeset your.name:2 labels:2.0,test
ALTER TABLE person ADD address VARCHAR(255) NULL;

--changeset your.name:3 labels:shopping_cart
ALTER TABLE person ADD favorite_color VARCHAR(255) NULL;

--changeset your.name:4
CREATE TABLE no_label (no_label_col VARCHAR(255) NULL);
{
  "databaseChangeLog": [
    {
      "changeSet": {
        "id": "1",
        "author": "your.name",
        "labels": "1.0,prod,shopping_cart",
        "changes": [
          {
            "createTable": {
              "tableName": "person",
              "columns": [
                {
                  "column": {
                    "name": "firstname",
                    "type": "varchar(255)"
                  }
                }
              ]
            }
          }
        ]
      }
    },
    {
      "changeSet": {
        "id": "2",
        "author": "your.name",
        "labels": "2.0,test",
        "changes": [
          {
            "createTable": {
              "tableName": "person",
              "columns": [
                {
                  "column": {
                    "name": "address",
                    "type": "varchar(255)"
                  }
                }
              ]
            }
          }
        ]
      }
    },
    {
      "changeSet": {
        "id": "3",
        "author": "your.name",
        "labels": "shopping_cart",
        "changes": [
          {
            "createTable": {
              "tableName": "person",
              "columns": [
                {
                  "column": {
                    "name": "favorite_color",
                    "type": "varchar(255)"
                  }
                }
              ]
            }
          }
        ]
      }
    },
    {
      "changeSet": {
        "id": "4",
        "author": "your.name",
        "changes": [
          {
            "createTable": {
              "tableName": "no_label",
              "columns": [
                {
                  "column": {
                    "name": "no_label_col",
                    "type": "varchar(255)"
                  }
                }
              ]
            }
          }
        ]
      }
    }
  ]
}
databaseChangeLog:
  - changeSet:
      id: '1'
      author: your.name
      labels: '1.0,prod,shopping_cart'
      changes:
        - createTable:
            tableName: person
            columns:
              - column:
                  name: firstname
                  type: varchar(255)
  - changeSet:
      id: '2'
      author: your.name
      labels: '2.0,test'
      changes:
        - addColumn:
            tableName: person
            columns:
              - column:
                  name: address
                  type: varchar(255)
  - changeSet:
      id: '3'
      author: your.name
      labels: 'shopping_cart'
      changes:
        - addColumn:
            tableName: person
            columns:
              - column:
                  name: favorite_color
                  type: varchar(255)
  - changeSet:
      id: '4'
      author: your.name
      changes:
        - createTable:
            tableName: no_label
            columns:
              - column:
                  name: no_label_col
                  type: varchar(255)
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog
    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
    xmlns:pro="http://www.liquibase.org/xml/ns/pro"
    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
        http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd
        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">

    <changeSet  author="your.name"  id="1"  labels="1.0,prod,shopping_cart">
        <createTable  tableName="person">
            <column  name="firstname"  type="VARCHAR(255)"/>
        </createTable>
    </changeSet>

    <changeSet  author="your.name"  id="2"  labels="2.0,test">
        <addColumn  tableName="person">
            <column  name="address"  type="VARCHAR(255)"/>
        </addColumn>
    </changeSet>

    <changeSet  author="your.name"  id="3"  labels="shopping_cart">
        <addColumn  tableName="person">
            <column  name="favorite_color"  type="VARCHAR(255)"/>
        </addColumn>
    </changeSet>

    <changeSet  author="your.name"  id="4">
        <createTable  tableName="no_label">
            <column  name="no_label_col"  type="VARCHAR(255)"/>
        </createTable>
    </changeSet>

</databaseChangeLog>

include and includeAll labels

You can specify the labels attribute in include and includeAll tags. If specified, the given label is added to all changesets in the included file(s).