Database Migrations : Flyway for Spring Boot projects
Published: 2024-06-06 18:18:50

Like Liquibase, Flyway can be used in 2 main manners for database migrations in Spring Boot projects, either on application startup or in an independent way.

In this post we will see how to configure Flyway and use it in the context of a Spring Boot project for both development and release phases, You can find examples in the repository available at : [Github Repository](https://github.com/Aharmaz/flyway-demo)

**Fundamental Concepts of Flyway** 

*Migration and Migration Script* :

A migration is the smallest coutable unit of change that Flyway can perform and register against a target database and it can involve one or more operations located on a file called migration script.

A migration in Flyway is equivalent to a changeset in Liquibase, however a migration script in Flyway is intended to host only a single migration, and a migration script in Liquibase can host multiple changesets 

In Flyway executing a migration is equivalent to executing the migration script hosting that migration

*flyway_schema_history Table* : 

This is the table Flyway creates on a database and uses for keeping track of what migrations has been already executed against that target database so that it does not run the same migration multiple times and it will be aware of what migrations it should run at a point of time (those that haven't been registered on the history table).

Each migration is identified by the filepath of the migration file where it is located. When Flyway runs a migration it calculate a checksum number for the content of that migration and stores it inside the flyway_schema_history table in order to make sure that the same migration won't be changed again 

If Flyway notices that a changeset has been modified after it has been applied by comparing the checksums, it will throw an error during the migration process

**Common Configuration** 

This consists of a folder on the resources directory of the project, then populate it with the migration files, in the example I have named it db/migrations : 

- V1_creating_persons_table.sql
- V2_inserting_rows_into_persons_table.sql

**Configuring Flyway to run migrations on application startup** 

This kind of behavior is commonly used at the development phase when a developer needs to update the state of the database he has on his local machine. Spring Boot offers some auto-configurations for launching the Flyway migration when the application is started.

For those auto-configuration to work we need to add some informations in the configuration file of the Spring Boot app related to local environments (application-local.yml) like the location of the database, the username and password of connection and the location of the migration files within the classpath of the application : 

```
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/flyway_demo
    username: postgres
    password: changemeinproduction
    driver-class-name: org.postgresql.Driver
  jpa:
    hibernate:
      ddl-auto: none
  flyway:
    locations: classpath:db/migrations
```

Then we should add flyway dependency in the pom.xml file of the project (build.gradle file if you are using Gradle) : 

```
<dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
</dependency>
```
Now when starting the application Spring Boot will notice the presence of the Flyway dependency on the classpath of the app and will uses the information in the configuration fi,le to trigger the auto-configuration that will be responsible for launching the migration process automcatically, here is an example of what you could see in the logs when the migration process is started : 

```
2024-06-06T19:01:09.407+01:00  INFO 3229 --- [           main] org.flywaydb.core.FlywayExecutor         : Database: jdbc:postgresql://localhost:5432/flyway_demo (PostgreSQL 16.0)
2024-06-06T19:01:09.428+01:00  WARN 3229 --- [           main] o.f.c.internal.database.base.Database    : Flyway upgrade recommended: PostgreSQL 16.0 is newer than this version of Flyway and support has not been tested. The latest supported version of PostgreSQL is 15.
2024-06-06T19:01:09.450+01:00  INFO 3229 --- [           main] o.f.c.i.s.JdbcTableSchemaHistory         : Schema history table "public"."flyway_schema_history" does not exist yet
2024-06-06T19:01:09.453+01:00  INFO 3229 --- [           main] o.f.core.internal.command.DbValidate     : Successfully validated 2 migrations (execution time 00:00.015s)
2024-06-06T19:01:09.486+01:00  INFO 3229 --- [           main] o.f.c.i.s.JdbcTableSchemaHistory         : Creating Schema History table "public"."flyway_schema_history" ...
2024-06-06T19:01:09.538+01:00  INFO 3229 --- [           main] o.f.core.internal.command.DbMigrate      : Current version of schema "public": << Empty Schema >>
2024-06-06T19:01:09.547+01:00  INFO 3229 --- [           main] o.f.core.internal.command.DbMigrate      : Migrating schema "public" to version "1 - creating persons table"
2024-06-06T19:01:09.606+01:00  INFO 3229 --- [           main] o.f.core.internal.command.DbMigrate      : Migrating schema "public" to version "2 - inserting rows into persons table"
2024-06-06T19:01:09.647+01:00  INFO 3229 --- [           main] o.f.core.internal.command.DbMigrate      : Successfully applied 2 migrations to schema "public", now at version v2 (execution time 00:00.042s)
```


**Configuring Flyway to run migrations independently from running the application**

This behavior is used when a new release of the software using a database is ready to be deployed, and a number of migrations must be applied on that database.

Maven provides a plugin for running Flyway migrations, this plugin will need to know about the database location, username and password of connection and the location of the migration files in the project folder, the way this can be configured is by adding a file on named flyway.conf to the resources folder of the Spring Boot project and then when adding the flyway maven plugin referencing the location of that file in the pom.xml : 

```
flyway.user=postgres
flyway.password=changemeinproduction
flyway.schemas=demo_flyway
flyway.url=jdbc:postgresql://localhost:5432/demo_flyway
flyway.locations=src/main/resources/db/migrations
```

```
<build>
  <plugins>
      <plugin>
         <groupId>org.flywaydb</groupId>
         <artifactId>flyway-maven-plugin</artifactId>
         <version>6.5.7</version>
         <configuration>
           <configFiles>
             <configFile>
               src/main/resources/flyway.conf
             </configFile>
           </configFiles>
         </configuration>
      </plugin>
  </plugins>
</build>
``` 

If we want to launch the migration process using the Flyway maven plugin we must set the property spring.flyway.enabled to false so that when the application is started no migration is executed : 

Finally we should run the migrations using the following command : 

``` 
./mvnw flyway:migrate
``` 
and we will be able to see the following logs indicating that the migrations has been executed succesfully.
``` 
[INFO] Scanning for projects...
[INFO] 
[INFO] ---------------------< ma.demo.flyway:flyway-demo >---------------------
[INFO] Building flyway-demo 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- flyway-maven-plugin:6.5.7:migrate (default-cli) @ flyway-demo ---
[INFO] Flyway Community Edition 6.5.7 by Redgate
[INFO] Database: jdbc:postgresql://localhost:5432/flyway_demo (PostgreSQL 16.0)
[WARNING] Flyway upgrade recommended: PostgreSQL 16.0 is newer than this version of Flyway and support has not been tested. The latest supported version of PostgreSQL is 12.
[INFO] Creating schema "flyway_demo" ...
[INFO] Creating Schema History table "flyway_demo"."flyway_schema_history" ...
[INFO] Current version of schema "flyway_demo": null
[INFO] Migrating schema "flyway_demo" to version 1 - creating persons table
[INFO] Migrating schema "flyway_demo" to version 2 - inserting rows into persons table
[INFO] Successfully applied 2 migrations to schema "flyway_demo" (execution time 00:00.066s)
[WARNING] Flyway upgrade recommended: PostgreSQL 16.0 is newer than this version of Flyway and support has not been tested. The latest supported version of PostgreSQL is 12.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.797 s
[INFO] Finished at: 2024-06-06T19:04:59+01:00
[INFO] ------------------------------------------------------------------------
``` 

**Conclusion**
Flyway simplifies database migrations by ensuring that changes are applied consistently, in the context of Spring Boot, it can be integrated easily to launch the migration process at the startup of the application and this helps developer focus more on building new features without worrying about the state databases.