Contexts

Contexts are expressions that control whether commands like update run certain changesets. You add contexts directly to changesets in your changelog and specify them at runtime using the --contexts attribute in the CLI. Context names are case-insensitive strings.

Although there are many use cases for contexts, it is common for contexts to be used to specify environments. For example, you may want to indicate that certain changesets should only be run in test or dev environments. Contexts are most useful if you want the changeset author to specify any complex filtering logic, rather than specifying this at runtime.

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

Usage

By default, a database update runs all changesets in the changelog, regardless of what you specify in the CLI. If you add a contextFilter to a changeset, it only runs when you specify that context in the CLI, but unmarked changesets still run. If you do not specify any contexts in the CLI at runtime, every changeset in your changelog runs, even if they have contextFilters attached.

For example, if you want to tag your environment and let the changesets contain the filter logic, set contextFilter in the changeset and use --contexts in the CLI.

Note: If you want to tag your changesets and control the filter logic in the CLI, use Labels instead of contexts.

Syntax

Note: Prior to Liquibase 4.16.0, the syntax to use in a changelog was context="test". In 4.16.0+, the correct syntax is contextFilter="test" to distinguish from the runtime argument. However, context is still a supported alias.

Context logic

In Liquibase 4.23+, you can specify a context using @ in addition to AND, OR, !, and parentheses in the changesets. This requires you to designate a context or label explicitly when Liquibase is run for the changeset to run. The attribute contextFilter: @test causes a changeset to not run if Liquibase runs without any contexts provided.

  • contextFilter="@test"

In Liquibase 3.2.0+, you can specify a context using AND, OR, !, and parentheses in the changesets. Without parentheses, the order of operations is !, AND, and then OR. For example:

  • contextFilter="!test"
  • contextFilter="v1.0 or map"
  • contextFilter="!qa and !main"

Using a "," to separate contexts works like an OR operation but with the highest precedence:

  • "test, qa" is the same as "test OR qa"
  • "test, qa and main" is the same as "(test) OR (qa and main)"

Running contexts

You can only specify context filtering logic in a changeset definition, but you can still specify multiple contexts when running Liquibase in the CLI. However, you can only list out all the contexts that apply to the current Liquibase run.

liquibase update --contexts="test" --changelog-file=example-changelog.xml

If your changelog includes several changesets with complex and simple context filters such as contextFilter="qa and main and !dev" for changeset 1 and contextFilter="test" for changeset 2, you need to pass the following on the command line to deploy them:

liquibase update --contexts="test,qa,main" --changelog-file=example-changelog.xml

Using contexts for test data

If you manage your test data with Liquibase, it is best practice to have this data in line with all your other changesets, but marked with a "test" contextFilter. When you want your test data inserted, run a database update and specify the "test" context in the CLI. When you need to migrate your production database, don't include the "test" context, and your test data will not be included.

Note: If you do not specify any contexts in the CLI at runtime, every changeset will be applied, including those marked with a "test" context.

If you have multiple test environments or test data sets, simply tag them with different contexts, like "min-test" and "integration-test".

Using contexts to control test data is better than having a separate changelogs tree because later Change Types and changes will be applied to existing test data the same as they are applied to production data. If you had a set of test data that was created and simply added after the database is set up, you would be constantly manually updating your test data scripts to keep them in line with the current database schema.

Multi-DBMS changelogs

If you need to use one changelog for multiple databases, and you only want specific changesets to run on each database, it is possible to use the contextFilter tag to filter them, and then run liquibase update --contexts="<dbname>" in your command line. However, this is not recommended. For example:

<changeSet  id="1-lawful-evil"  author="adrian" contextFilter="postgres">
    <createTable  tableName="my_table">
        <column  name="id"  type="int"/>
    </createTable>
</changeSet>

Instead, it is a best practice to use the dbms tag to differentiate changesets by database type, and then run liquibase update in your command line. This is a clearer use of contexts and decreases the possibility of errors. You can use contextFilter and dbms on the same changeset, but only dbms should refer to your database type. For example:

<changeSet  id="1-lawful-good"  author="adrian" dbms="postgres">
    <createTable  tableName="my_postgres_table">
        <column  name="id"  type="int"/>
    </createTable>
</changeSet>
<changeSet  id="2-lawful-good"  author="adrian" dbms="oracle">
    <createTable  tableName="my_oracle_table">
        <column  name="id"  type="int"/>
    </createTable>
</changeSet>
<changeSet  id="3-lawful-good"  author="adrian" dbms="oracle" contextFilter="test">
    <createTable  tableName="my_oracle_test_table">
        <column  name="id"  type="int"/>
    </createTable>
</changeSet>

Default context

You can specify a contextFilter attribute in the root DATABASECHANGELOG node to assign that context to all changesets in the changelog by default.

The specified contextFilter will have AND with any contextFilters specified in changesets within the changelog file.

include and includeAll contexts

You can specify the contextFilter attribute in <include> or <includeAll> tags. If specified, the given contextFilter is added to all changesets in the included file(s).

Related links