Design Your Liquibase Project

Your changelog is the core of your Liquibase project. While you can use one changelog for all your deployments, this may not scale well. Instead, you can use multiple changelogs for different purposes. To organize multiple changelogs, you can use the include and includeAll tags to create a root (main/parent) changelog and one or more nested (child) changelogs. This document explains some best practices on structuring your changelogs.

Prerequisites

If you're new to Liquibase, make sure you understand the fundamentals before creating your own project:

  1. Install Liquibase – Download Liquibase on your machine
  2. Get Started with Liquibase – Learn how to use Liquibase with an example database

Create a project

The Get Started guide linked previously shows you how Liquibase deployments work using a sample database and changelog. However, your organization's needs go beyond a demonstration. To create a new Liquibase project, run the init project command in your command line:

liquibase init project

This generates a new changelog and liquibase.properties file that you can customize and expand. You can use the default settings or specify your own. For more information on command arguments, see the init project page.

Choose a schema design pattern

You can use Liquibase in two ways:

  • Shared schema: All developers work in a single, shared database schema
  • Multi-schema: Each team works in a different database schema

To choose what's best for your organization, consider the processes your developers currently use to deploy changes to the database.

Shared schema

Using a single schema can simplify your database structure and standardization process. However, a large single-schema database with complex object structures may require you to write long queries that negatively affect performance.

Everyone sharing a schema must agree on a deployment process. One model is to keep all schema content in a single repository owned by one team. When other teams want to make changes, they submit pull requests from their source control tool. Alternatively, each team can work in their own directory in the schema and try to minimize cross-team dependencies.

Multiple schemas

Using multiple schemas may make it easier to organize your data, prevent conflicts with source control merges or broken dependencies, help you store data backups, and let you customize user and application permissions for each schema.

However, using multiple schemas means you may have to duplicate some of your data, which can make consistency more difficult. Depending on your automation tooling and workflow, you may also need to call Liquibase multiple times to send your code to production, which requires extra maintenance from your DevOps team.

Choose a changelog structure

It is a best practice to create a simple root changelog that you don't modify directly. Instead, define nested changelogs with the include and includeAll tags and make changes to them. You can modify and deploy the nested changelogs independently or deploy all changes in a single update from the root changelog.

There are two common changelog design patterns, object-oriented and release-oriented. The design you choose should correspond to the structure of your existing code repository and workflow.

Object-oriented

In an object-oriented changelog structure, you create one changelog per object or object type. For example:

com
  example
    db
      changelog
        changelog-root.xml
        changelog-index.xml
        changelog-procedure.xml
        changelog-table.xml
        changelog-view.xml

In this example, we have a root changelog called changelog-root.xml which contains include tags referencing changelog-index.xml, changelog-procedure.xml, changelog-table.xml, and changelog-view.xml.

Alternatively, you can create directories for each type of object, each containing one or more changelogs per particular database object:

com
  example
    db
      changelog
        changelog-root.xml
        changelog-indexes
          my-favorite-index.xml
          that-other-index.xml
        changelog-tables
          employees.xml
          customers.xml

In this example, we have a root changelog called changelog-root.xml which contains includeAll tags referencing the directories /changelog-indexes and /changelog-tables. The changelogs you modify regularly are contained in the nested directories rather than in the overarching /changelog directory.

An object-oriented changelog format allows you to easily see changes made over time to specific objects (like a particular table) or groups of objects (like all tables in your database). It also makes it easier to roll back changes to particular objects without worrying about unrelated changes in the changelog.

If all your developers work in the same changelog, they may experience frequent source control merge conflicts. However, if developers work in different changelogs for each object, they may be less likely to overwrite each other's code.

Release-oriented

In a release-oriented changelog structure, you create one changelog per release or release group. For example:

com
  example
    db
      changelog
        changelog-root.xml
        changelog-1.0.xml
        changelog-1.1.xml
        changelog-2.0.xml

In this example, we have a root changelog called changelog-root.xml which contains include tags referencing changelog-1.0.xml, changelog-1.1.xml, and changelog-2.0.xml.

Alternatively, you can create directories for each major release (or other release group), each containing one or more changelogs per minor release:

com
  example
    db
      changelog
        changelog-root.xml
        changelog-1.x
          changelog-1.0.xml
          changelog-1.1.xml
        changelog-2.x
          changelog-2.0.xml

In this example, we have a root changelog called changelog-root.xml which contains includeAll tags referencing the directories /changelog-1.x and /changelog-2.x. The changelogs you modify for a particular release are contained in the nested directories rather than in the overarching /changelog directory.

A release-oriented changelog structure lets you bundle all content associated with a release in one place. However, this design can be difficult to maintain. If you want to see changes made to a particular object over time, the release-oriented structure requires you to look in multiple locations for that information.

Additionally, having a single changelog per release (even minor release) may lead to more frequent source control merge conflicts. You can solve this by creating multiple changelogs within each release directory, such as /changelog-1.0/indexes.xml and /changelog-1.0/tables.xml. However, this structure may be more complicated to navigate and maintain than a pure object-oriented changelog design.

Prepare for deployment

  • When you use the includeAll tag in your root changelog, you must ensure your file naming convention is consistent. Liquibase sorts pending scripts in alphanumeric order and then deploys them in that order.
  • You can specify filtering logic to control which changesets in your changelog are executed at runtime by using preconditions, contexts, labels, and other changelog attributes like runAlways and runOnChange. For more information, see Changelog Attributes.
  • When you publish updates to your software, it is a best practice to release separate artifacts for each step in your development pipeline, such as artifacts for dev, qa, and prod. You can easily version artifacts and run checks on them with automation tools. Alternatively or in addition, you can use contexts to group changesets into environments and labels to mark changesets as belong to specific features. Simulating environments with branches in source control is not recommended.

Next steps

  1. Liquibase Database Tutorials – Configure Liquibase to work with your own database
  2. Best Practices – Read about best practices to follow with Liquibase