'Spring Boot: run liquibase migrations without starting app

In Spring Boot, the documentation seems to encourage running migrations on app startup.

This is fine, but sometimes app startup may have side effects / dependencies that I don't want to bother with - I just want to run the migrations on their own. Think just setting up a local dev database, to poke around in it, without even running the app.

In Dropwizard by comparison, running migrations alone is straightforward with built in arguments for the app, like so

java -jar hello-world.jar db migrate helloworld.yml

Is there anything equivalent for Spring Boot? Or do I just have to drop down and run liquibase directly?

I'm interested in a direct answer, but also kind of interested in seeing if I'm misunderstanding something at a higher level - like perhaps this approach of running on startup is generally 'better' for some reasons I haven't discovered yet, so you're encouraged solely to do it this way by Spring Boot as a design choice.



Solution 1:[1]

I know this is an old question, but in case someone else stumbles upon it, this might be useful.

You can define a command line argument for your app, that you will use to only spin up a portion of the app context that will run migration.

Here's an example in Kotlin:

import org.springframework.boot.ApplicationContextFactory.ofContextClass
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration
import org.springframework.boot.builder.SpringApplicationBuilder
import org.springframework.boot.runApplication
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Import

@SpringBootApplication
class Application

@Import(DataSourceAutoConfiguration::class, LiquibaseAutoConfiguration::class)
class LiquibaseInit

fun main(args: Array<String>) {
    if (args.contains("dbinit")) {
        SpringApplicationBuilder(LiquibaseInit::class.java)
            .contextFactory(ofContextClass(AnnotationConfigApplicationContext::class.java))
            .run(*args)
        return
    }

    runApplication<Application>(*args)
}

Note: with Spring Boot 2.4.0 and earlier use SpringApplicationBuilder#contextClass instead of contextFactory.

We have 2 classes declared here: Application (the main app class having @SpringBootApplication annotation) and LiquiBaseInit (having @DataSourceAutoConfiguration and @LiquibaseAutoConfiguration), the first one will spin up the whole context, while the latter will only spin up the beans necessary for Liquibase to run migration.

Inside the main function we check if the arguments array has a string dbinit and if it is there we start an application context out of LiquiBaseInit class.

Now you can run migration with your jar file like this:

java -jar hello-world.jar dbinit

If you're going to run your app in Kubernetes, you might also want to check out this article in my blog: https://blog.monosoul.dev/2021/12/26/using-liquibase-with-kubernetes/ .

Solution 2:[2]

This answer mentions a hook that runs after Liquibase. In that question, it was used to populate the database, probably with test or default values.

@Bean
@DependsOn("liquibase")
public YourBean yourBean() {
    return new YourBean();
}

static class YourBean {

    @PostConstruct
    public void shutdown() {
         // Exit your application here.
         );
    }

}

That could work. I don't know, you'd probably even have access to the liquibase mode and only shut down when it was "create."

Solution 3:[3]

You can use different Spring profiles: For instance, use a profile called 'init' which will activate the 'liquibase' profile.

application.yml: (disable Liquibase by default)

spring:
  liquibase:
    enabled: false

application-init.yml: (does not run a web container, so spring will close automatically after startup)

spring:
  profiles:
    include: liquibase
  main:
    web-application-type: none

spring-liquibase.yml: (enables liquibase)

spring:
  liquibase:
    enabled: true
    change-log: classpath:/db/changelog/changelog.xml

This setup allows you to run Liquibase as an init container (spring.profiles.active=init), but if you want to you can still run Liquibase as part of your web-app (spring.profiles.active=liquibase).

Solution 4:[4]

In general, it might be just less work to run migrations on app start, especially if you're using Spring Boot and its all set up for you. You can then just stop the app.

However if you really would like to run migrations without the Spring Boot app, you can use the Liquibase Gradle and Maven plugins: https://github.com/liquibase/liquibase-gradle-plugin https://docs.liquibase.com/tools-integrations/maven/home.html

This will require you to set up the database credentials in another config file, in addition to your application config, so that the plugins can connect to the database.

Solution 5:[5]

For this purpose we created our own script that allows not only to gen migrations but also to manually apply them, however it could be applied only from gradle, see: https://github.com/Wissance/SpringUu

to apply update we use following command:

.\gradlew.bat update -PrunList='changesApply'

to specify db connection edit gradle section changesApply

For more details about our tool see article:

https://m-ushakov.medium.com/code-first-with-spring-boot-hibernate-and-liquibase-48f5c9998d95

Solution 6:[6]

U can set up and configure maven liquibase plugin: https://docs.liquibase.com/tools-integrations/maven/commands/home.html

It allows to use migrations without starting spring boot app itself

can be set up as part of building artifact or like separate task

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 knallfrosch
Solution 3 blagerweij
Solution 4 Michael
Solution 5 Michael Ushakov
Solution 6 Oleg Maksymuk