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:
- Install Liquibase – Download Liquibase on your machine
- 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.
Note: Your root changelog can be an XML, YAML, or JSON file. In Liquibase Pro 4.28.0+, your root changelog can also be a SQL file. However, your root changelog cannot be a formatted Mongo (JS) file.
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.yaml
changelog-index.sql
changelog-procedure.sql
changelog-table.sql
changelog-view.sql
In this example, we have a root changelog called changelog-root.yaml
which contains include
tags referencing changelog-index.sql
, changelog-procedure.sql
, changelog-table.sql
, and changelog-view.sql
.
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.yaml
changelog-indexes
my-favorite-index.sql
that-other-index.sql
changelog-tables
employees.sql
customers.sql
In this example, we have a root changelog called changelog-root.yaml
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.yaml
changelog-1.0.sql
changelog-1.1.sql
changelog-2.0.sql
In this example, we have a root changelog called changelog-root.yaml
which contains include
tags referencing changelog-1.0.sql
, changelog-1.1.sql
, and changelog-2.0.sql
.
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.yaml
changelog-1.X
changelog-1.0.sql
changelog-1.1.sql
changelog-2.X
changelog-2.0.sql
In this example, we have a root changelog called changelog-root.yaml
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.sql
and /changelog-1.0/tables.sql
. 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
andrunOnChange
. For more information, see Changelog Attributes.
Next steps
- Liquibase Database Tutorials – Configure Liquibase to work with your own database
- Best Practices – Read about best practices to follow with Liquibase