Liquibase
Spring Boot
DevOps
Environment Configuration
Software Deployment

How to divide Liquibase package structure for dev and prod environment in Spring Boot?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Liquibase works best in Spring Boot when the changelog structure reflects the deployment policy instead of mixing every environment concern into one file tree. The usual goal is to keep schema changes shared across environments, while isolating environment-specific data loads, test helpers, and optional features so development and production can evolve safely.

Keep One Shared Schema History

The first design rule is that database schema history should usually be shared, not duplicated. Development and production should not have different versions of the same core table definition unless you are intentionally running different applications.

A simple structure looks like this:

text
1src/main/resources/db/changelog/
2  db.changelog-master.yaml
3  common/
4    001-create-user-table.yaml
5    002-add-indexes.yaml
6  dev/
7    901-seed-test-users.yaml
8  prod/
9    951-prod-only-backfill.yaml

The common directory holds schema changes that belong everywhere. The environment directories hold changes that are explicitly environment-specific.

That keeps the main evolution path easy to reason about and avoids the trap of having two unrelated changelog trees that drift apart.

Use One Master Changelog With Includes

The usual pattern is to keep one master changelog and include shared files first.

yaml
1databaseChangeLog:
2  - include:
3      file: db/changelog/common/001-create-user-table.yaml
4  - include:
5      file: db/changelog/common/002-add-indexes.yaml

Then include environment-specific files only when their context should apply.

yaml
1databaseChangeLog:
2  - include:
3      file: db/changelog/common/001-create-user-table.yaml
4  - include:
5      file: db/changelog/common/002-add-indexes.yaml
6  - include:
7      file: db/changelog/dev/901-seed-test-users.yaml
8      context: dev
9  - include:
10      file: db/changelog/prod/951-prod-only-backfill.yaml
11      context: prod

This approach keeps the dependency order explicit and makes it much easier to audit what runs in each environment.

Use Contexts for Environment-Specific Changes

Liquibase contexts are the cleanest way to tag changesets that should run only in selected environments.

yaml
1databaseChangeLog:
2  - changeSet:
3      id: seed-dev-users
4      author: app-team
5      context: dev
6      changes:
7        - insert:
8            tableName: users
9            columns:
10              - column:
11                  name: username
12                  value: dev_admin

In Spring Boot, activate the right context through configuration.

yaml
1spring:
2  liquibase:
3    change-log: classpath:db/changelog/db.changelog-master.yaml
4    contexts: dev

and for production:

yaml
1spring:
2  liquibase:
3    change-log: classpath:db/changelog/db.changelog-master.yaml
4    contexts: prod

This is much safer than maintaining two different master changelogs that duplicate most of the same history.

Separate Schema From Data Seeding

A common source of chaos is putting development seed data next to structural schema changes without any clear boundary. A better rule is:

  • schema lives in shared changelogs
  • test and demo data lives in context-gated changelogs
  • one-off production backfills are isolated and clearly named

That separation matters because production migrations should be boring and predictable. Development conveniences such as sample users or fake reference data should not even be eligible to run there.

Use Spring Profiles to Select Liquibase Settings

Spring Boot profiles are a natural way to keep the Liquibase configuration aligned with the application environment.

yaml
1# application-dev.yaml
2spring:
3  liquibase:
4    contexts: dev
yaml
1# application-prod.yaml
2spring:
3  liquibase:
4    contexts: prod

This avoids hardcoding the environment choice inside the changelog itself and keeps deployment behavior visible in the Spring configuration that already controls the environment.

Common Pitfalls

The biggest mistake is splitting the schema history completely into separate dev and prod trees. That usually leads to divergence, duplication, and confusion about which changes are the real history of the database.

Another issue is using environment-specific directories without contexts or labels, then assuming the right files will somehow be skipped automatically.

Teams also often mix test data, schema changes, and one-time operational fixes in one flat folder with no naming convention. That makes production review harder than it needs to be.

Finally, do not use Liquibase package structure as a substitute for deployment discipline. The file layout helps, but the real safety comes from shared schema history plus explicit environment gating.

Summary

  • Keep one shared schema history for changes that belong in every environment.
  • Use separate directories only for clearly environment-specific changes such as seed data or prod-only backfills.
  • Drive environment selection with Liquibase contexts and Spring profiles.
  • Avoid duplicating dev and prod master changelogs when most schema history is the same.
  • Separate schema evolution from data seeding so production migrations stay predictable.

Course illustration
Course illustration

All Rights Reserved.