Skip Navigation
Show nav
Heroku Dev Center
  • Get Started
  • Documentation
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
  • Documentation
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Heroku Blog

    Find out what's new with Heroku on our blog.

    Visit Blog
  • Log inorSign up
View categories

Categories

  • Heroku Architecture
    • Dynos (app containers)
    • Stacks (operating system images)
    • Networking & DNS
    • Platform Policies
    • Platform Principles
  • Command Line
  • Deployment
    • Deploying with Git
    • Deploying with Docker
    • Deployment Integrations
  • Continuous Delivery
    • Continuous Integration
  • Language Support
    • Node.js
    • Ruby
      • Working with Bundler
      • Rails Support
    • Python
      • Background Jobs in Python
      • Working with Django
    • Java
      • Working with Maven
      • Java Database Operations
      • Working with the Play Framework
      • Working with Spring Boot
      • Java Advanced Topics
    • PHP
    • Go
      • Go Dependency Management
    • Scala
    • Clojure
  • Databases & Data Management
    • Heroku Postgres
      • Postgres Basics
      • Postgres Getting Started
      • Postgres Performance
      • Postgres Data Transfer & Preservation
      • Postgres Availability
      • Postgres Special Topics
    • Heroku Data For Redis
    • Apache Kafka on Heroku
    • Other Data Stores
  • Monitoring & Metrics
    • Logging
  • App Performance
  • Add-ons
    • All Add-ons
  • Collaboration
  • Security
    • App Security
    • Identities & Authentication
    • Compliance
  • Heroku Enterprise
    • Private Spaces
      • Infrastructure Networking
    • Enterprise Accounts
    • Enterprise Teams
    • Heroku Connect (Salesforce sync)
      • Heroku Connect Administration
      • Heroku Connect Reference
      • Heroku Connect Troubleshooting
    • Single Sign-on (SSO)
  • Patterns & Best Practices
  • Extending Heroku
    • Platform API
    • App Webhooks
    • Heroku Labs
    • Building Add-ons
      • Add-on Development Tasks
      • Add-on APIs
      • Add-on Guidelines & Requirements
    • Building CLI Plugins
    • Developing Buildpacks
    • Dev Center
  • Accounts & Billing
  • Troubleshooting & Support
  • Integrating with Salesforce
  • Language Support
  • Java
  • Java Database Operations
  • Running Database Migrations for Java Apps

Running Database Migrations for Java Apps

English — 日本語に切り替える

Last updated June 05, 2020

Table of Contents

  • Using Liquibase
  • Using Flyway
  • Further Reading

Most database-backed applications will need to change their database schema during the course of operations. These changes are often controlled by a process called migrations or evolutions.

In this article, you’ll learn how to use two tools, Liquibase and Flyway, to run database migrations for a Java application on Heroku.

Using Liquibase

There are many ways to run Liquibase. It provides a Maven plugin, a standalone command-line tool, a Hibernate plugin, and a Spring Bean. In this article, we’ll discuss the best mechanisms for use on Heroku.

Running Liquibase automatically with Spring

Liquibase provides a very convenient SpringLiquibase bean that automatically runs your migrations on startup if they are in the correct location.

If you are using Spring Boot, you only need to include the liquibase-core dependency and put your change log in src/resources/db/changelog/db.changelog-master.yaml, as demonstrated in this Spring and Liquibase sample application.

Upon startup, you will see something like this in your logs:

2015-10-20T02:00:51.937179+00:00 app[web.1]: 2015-10-20 02:00:51.936  INFO 3 --- [main] liquibase : Successfully acquired change log lock
2015-10-20T02:00:55.419669+00:00 app[web.1]: 2015-10-20 02:00:55.419  INFO 3 --- [main] liquibase : Reading from public.databasechangelog
2015-10-20T02:00:55.571104+00:00 app[web.1]: 2015-10-20 02:00:55.555  INFO 3 --- [main] liquibase : Successfully released change log lock

However, running migrations at startup does add to your app’s boot time and may cause you to exceed the boot-timeout limit imposed by Heroku. If so, you may find that running the migrations in the Heroku release phase is preferable.

Running Liquibase with the Maven Plugin

The Liquibase migrations can be run in Heroku release phase using the Liquibase Maven Plugin by adding the following plugin configuration to your pom.xml:

<plugin>
  <groupId>org.liquibase</groupId>
  <artifactId>liquibase-maven-plugin</artifactId>
  <configuration>
    <changeLogFile>src/main/resources/db/changelog/db.changelog-master.yaml</changeLogFile>
    <url>${env.JDBC_DATABASE_URL}</url>
  </configuration>
</plugin>

Next, make sure you’re using the Maven Wrapper in your project. If you’re not already, you can add it by running:

$ mvn -N io.takari:maven:wrapper
$ git add mvnw .mvn
$ git commit -m "Added maven wrapper"

With this in place, you can add a process entry to your Procfile that will run the migrations in the release phase of deployment:

release: ./mvnw liquibase:update

However, this will require downloading all of the Liquibase dependencies each time release phase runs because the Maven .m2 cache is not included in your app’s slug. If that overhead is prohibitive you may want to run Liquibase without Maven.

Running Liquibase with the command-line tool

Your Liquibase migrations can be run in Heroku release phase using the Liquibase command-line tool. To use this tool, you’ll need to include the Liquibase JAR file in your slug by adding the following plugin configuration to your Maven pom.xml:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-dependency-plugin</artifactId>
  <executions>
    <execution>
      <id>copy-dependencies</id>
      <phase>package</phase>
      <goals><goal>copy</goal></goals>
      <configuration>
        <artifactItems>
          <artifactItem>
            <groupId>org.liquibase</groupId>
            <artifactId>liquibase-core</artifactId>
            <version>3.4.1</version>
            <destFileName>liquibase.jar</destFileName>
          </artifactItem>
          <artifactItem>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>1.13</version>
            <outputDirectory>${project.build.directory}/dependency/lib</outputDirectory>
          </artifactItem>
          <artifactItem>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.4-1204-jdbc41</version>
            <destFileName>postgres.jar</destFileName>
          </artifactItem>
        </artifactItems>
      </configuration>
    </execution>
  </executions>
</plugin>

This will copy the JAR file to target/dependency/liquibase.jar during the Maven package goal. With this in place, you can add a process entry to your Procfile that will run the migrations in the release phase of deployment:

release: java -jar target/dependency/liquibase.jar --changeLogFile=src/main/resources/db/changelog/db.changelog-master.yaml --url=$JDBC_DATABASE_URL --classpath=target/dependency/postgres.jar update

Liquibase is not the only migration engine for Java. You can also use Flyway.

Using Flyway

Flyway provides several mechanisms for running migrations including a command-line tool, Maven plugin, Gradle plugin and an SBT plugin. In this article, we’ll discuss the best mechanisms for use on Heroku.

Running Flyway automatically with Spring

You can run Flyway automatically by including the flyway-core dependency in your app and putting your migration scripts in src/main/resources/db/migration/, as demonstrated in this Spring and Flyway sample application.

However, running migrations at startup does add to your app’s boot time and may cause you to exceed the boot-timeout limit imposed by Heroku. If this is the case, you may find that running the migrations from Heroku release phase preferable.

Running Flyway with the Maven Plugin

You can also run the Flyway Maven Plugin from Heroku’s release phase. First, add the plugin to you pom.xml:

<plugin>
  <groupId>org.flywaydb</groupId>
  <artifactId>flyway-maven-plugin</artifactId>
  <configuration>
    <url>${env.JDBC_DATABASE_URL}</url>
  </configuration>
</plugin>

Next, make sure you’re using the Maven Wrapper in your project. If you’re not already, you can add it by running:

$ mvn -N io.takari:maven:wrapper
$ git add mvnw .mvn
$ git commit -m "Added maven wrapper"

With this in place, you can add a process entry to your Procfile that will run the migrations in the release phase of deployment:

release: ./mvnw flyway:migrate

However, this will require downloading all of the Flyway dependencies each time release phase runs because the Maven .m2 cache is not included in your app’s slug. If that overhead is prohibitive you may want to run Flyway without Maven.

Running Flyway with the Java API

To use the Flyway Java API, create a simple class with a main method, such as this:

package sample.flyway;

import org.flywaydb.core.Flyway;

public class Migrations {
    public static void main(String[] args) throws Exception {
        Flyway flyway = new Flyway();
        flyway.setDataSource(System.getenv("JDBC_DATABASE_URL"),
                             System.getenv("JDBC_DATABASE_USERNAME"),
                             System.getenv("JDBC_DATABASE_PASSWORD"));
        flyway.migrate();
    }
}

Then copy the flyway JAR file into your slug file by adding this plugin configuration to your pom.xml file:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-dependency-plugin</artifactId>
  <executions>
    <execution>
      <id>copy-dependencies</id>
      <phase>package</phase>
      <goals><goal>copy</goal></goals>
      <configuration>
        <artifactItems>
          <artifactItem>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
            <version>3.2.1</version>
            <destFileName>flyway.jar</destFileName>
          </artifactItem>
          <artifactItem>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.4-1204-jdbc41</version>
            <destFileName>postgres.jar</destFileName>
          </artifactItem>
        </artifactItems>
      </configuration>
    </execution>
  </executions>
</plugin>

This will copy the JAR file to target/dependency/flyway.jar during the Maven package goal. With this in place, you can add a process entry to your Procfile that will run the migrations:

release: java -cp target/spring-boot-sample-flyway-1.0.0.jar:target/dependency/* sample.flyway.Migrations

This will run the migrations during the Heroku release phase. You can also run the migrations manually with this command:

$ heroku run release

Further Reading

For more information, see the official documentation pages for each of these open source projects:

  • Liquibase
  • Flyway

And you can read more about Connecting to Relational Databases on Heroku with Java in the Dev Center.

Keep reading

  • Java Database Operations

Feedback

Log in to submit feedback.

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Podcasts
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing

Subscribe to our monthly newsletter

Your email address:

  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Heroku Podcasts
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Facebook
  • Instagram
  • Github
  • LinkedIn
  • YouTube
Heroku is acompany

 © Salesforce.com

  • heroku.com
  • Terms of Service
  • Privacy
  • Cookies
  • Cookie Preferences