Micronaut Flyway

Integration between Micronaut and Flyway

Version: 7.2.0-SNAPSHOT

1 Introduction

To use the Micronaut’s integration with Flyway you must have the micronaut-flyway dependency on your classpath:

implementation("io.micronaut.flyway:micronaut-flyway")
<dependency>
    <groupId>io.micronaut.flyway</groupId>
    <artifactId>micronaut-flyway</artifactId>
</dependency>

In addition to the base Flyway dependency that will be included automatically with the above, some databases require an additional database-specific Flyway library. Include one of the following dependencies as needed for your database:

runtimeOnly("org.flywaydb:flyway-mysql")
<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-mysql</artifactId>
</dependency>

runtimeOnly("org.flywaydb:flyway-database-oracle")
<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-database-oracle</artifactId>
</dependency>

runtimeOnly("org.flywaydb:flyway-database-postgresql")
<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-database-postgresql</artifactId>
</dependency>

runtimeOnly("org.flywaydb:flyway-sqlserver")
<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-sqlserver</artifactId>
</dependency>

You also need dependencies for the JDBC connection pool and the JDBC driver specific to your database as described in Configuring a JDBC DataSource.

2 Release History

For this project, you can find a list of releases (with release notes) here:

3 Configuration

3.1 JPA/Hibernate

You can define Flyway configuration for each datasource. The following example demonstrates using it:

src/main/resources/application.yml
datasources.default.url=jdbc:h2:mem:flywayDb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
datasources.default.username=sa
datasources.default.password=
datasources.default.driverClassName=org.h2.Driver
jpa.default.packages-to-scan[0]=example.micronaut
jpa.default.properties.hibernate.hbm2ddl.auto=none
jpa.default.properties.hibernate.show_sql=true
flyway.datasources.default.enabled=true
datasources:
  default:
    url: 'jdbc:h2:mem:flywayDb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE'
    username: 'sa'
    password: ''
    driverClassName: 'org.h2.Driver'
jpa:
  default:
    packages-to-scan:
      - 'example.micronaut'
    properties:
      hibernate:
        hbm2ddl:
          auto: none
        show_sql: true
flyway:
  datasources:
    default:
      enabled: true
[datasources]
  [datasources.default]
    url="jdbc:h2:mem:flywayDb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"
    username="sa"
    password=""
    driverClassName="org.h2.Driver"
[jpa]
  [jpa.default]
    packages-to-scan=[
      "example.micronaut"
    ]
    [jpa.default.properties]
      [jpa.default.properties.hibernate]
        show_sql=true
        [jpa.default.properties.hibernate.hbm2ddl]
          auto="none"
[flyway]
  [flyway.datasources]
    [flyway.datasources.default]
      enabled=true
datasources {
  'default' {
    url = "jdbc:h2:mem:flywayDb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"
    username = "sa"
    password = ""
    driverClassName = "org.h2.Driver"
  }
}
jpa {
  'default' {
    packagesToScan = ["example.micronaut"]
    properties {
      hibernate {
        hbm2ddl {
          auto = "none"
        }
        show_sql = true
      }
    }
  }
}
flyway {
  datasources {
    'default' {
      enabled = true
    }
  }
}
{
  datasources {
    default {
      url = "jdbc:h2:mem:flywayDb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"
      username = "sa"
      password = ""
      driverClassName = "org.h2.Driver"
    }
  }
  jpa {
    default {
      packages-to-scan = ["example.micronaut"]
      properties {
        hibernate {
          hbm2ddl {
            auto = "none"
          }
          show_sql = true
        }
      }
    }
  }
  flyway {
    datasources {
      default {
        enabled = true
      }
    }
  }
}
{
  "datasources": {
    "default": {
      "url": "jdbc:h2:mem:flywayDb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE",
      "username": "sa",
      "password": "",
      "driverClassName": "org.h2.Driver"
    }
  },
  "jpa": {
    "default": {
      "packages-to-scan": ["example.micronaut"],
      "properties": {
        "hibernate": {
          "hbm2ddl": {
            "auto": "none"
          },
          "show_sql": true
        }
      }
    }
  },
  "flyway": {
    "datasources": {
      "default": {
        "enabled": true
      }
    }
  }
}
  • Disable schema DDL creation with jpa.default.properties.hibernate.hbm2ddl.auto set to 'none'

  • Define flyway configuration under flyway.datasources key.

  • Configure flyway configuration for default datasource under datasources.default and jpa.default

  • Enable the flyway migrations for the default datasource under flyway.datasources.default

You need to put the migrations in Flyway default directory src/main/resources/db/migration. If you want to modify the default directory or add more, you need to set the property flyway.datasources.default.locations. For example:
flyway.datasources.default.enabled=true
flyway.datasources.default.locations[0]=classpath:databasemigrations
flyway.datasources.default.locations[1]=classpath:other
flyway:
  datasources:
    default:
      enabled: true
      locations:
        - classpath:databasemigrations
        - classpath:other
[flyway]
  [flyway.datasources]
    [flyway.datasources.default]
      enabled=true
      locations=[
        "classpath:databasemigrations",
        "classpath:other"
      ]
flyway {
  datasources {
    'default' {
      enabled = true
      locations = ["classpath:databasemigrations", "classpath:other"]
    }
  }
}
{
  flyway {
    datasources {
      default {
        enabled = true
        locations = ["classpath:databasemigrations", "classpath:other"]
      }
    }
  }
}
{
  "flyway": {
    "datasources": {
      "default": {
        "enabled": true,
        "locations": ["classpath:databasemigrations", "classpath:other"]
      }
    }
  }
}
  • The locations properties configure Flyway to look for migrations in the directories src/main/resources/databasemigrations and src/main/resources/other.

Now, in the migration directory you can include your migrations:

src/main/resources/db/migration/V1__create-books-schema.sql
create table books(
    id bigint auto_increment primary key,
    name varchar(255) not null,
    constraint UK_name unique (name)
);
Starting with Micronaut 1.1.3 it is not necessary to define the jpa configuration if you only want to run the migrations but not actually use JPA.

Run migrations manually

If you need more control to decide when the migrations are executed it is possible to configure the application like this:

flyway.enabled=true
flyway.datasources.default.enabled=false
flyway:
  enabled: true
  datasources:
    default:
      enabled: false
[flyway]
  enabled=true
  [flyway.datasources]
    [flyway.datasources.default]
      enabled=false
flyway {
  enabled = true
  datasources {
    'default' {
      enabled = false
    }
  }
}
{
  flyway {
    enabled = true
    datasources {
      default {
        enabled = false
      }
    }
  }
}
{
  "flyway": {
    "enabled": true,
    "datasources": {
      "default": {
        "enabled": false
      }
    }
  }
}
  • Enable Flyway and disable flyway migrations for your specific datasource

Now you can inject the FlywayMigrator bean and call manually the method run to execute the migrations when you want.

3.2 Additional configuration

There are several options available for configuration:

🔗
Table 1. Configuration Properties for FlywayConfigurationProperties
Property Type Description

flyway.datasources.*.enabled

boolean

Set whether this flyway configuration is enabled. Default value (true).

flyway.datasources.*.async

boolean

Whether the flyway migrations should run asynchronously. Default value: false.

flyway.datasources.*.clean-schema

boolean

Whether Flyway will clean the schema before running the migrations. Default value (false).

flyway.datasources.*.url

java.lang.String

The JDBC url of the database to migrate.

flyway.datasources.*.user

java.lang.String

The user of the database to migrate.

flyway.datasources.*.username

java.lang.String

The username of the database to migrate

flyway.datasources.*.password

java.lang.String

The password of the database to migrate.

flyway.datasources.*.report-filename

java.lang.String

flyway.datasources.*.environment

java.lang.String

flyway.datasources.*.working-directory

java.lang.String

flyway.datasources.*.error-overrides

java.lang.String

flyway.datasources.*.group

boolean

flyway.datasources.*.installed-by

java.lang.String

flyway.datasources.*.loggers

java.lang.String

flyway.datasources.*.mixed

boolean

flyway.datasources.*.validate-migration-naming

boolean

flyway.datasources.*.validate-on-migrate

boolean

flyway.datasources.*.clean-on-validation-error

boolean

flyway.datasources.*.clean-disabled

boolean

flyway.datasources.*.execute-in-transaction

boolean

flyway.datasources.*.detect-encoding

boolean

flyway.datasources.*.default-schema

java.lang.String

flyway.datasources.*.schemas

java.lang.String

flyway.datasources.*.table

java.lang.String

flyway.datasources.*.tablespace

java.lang.String

flyway.datasources.*.placeholder-replacement

boolean

flyway.datasources.*.placeholders

java.util.Map

flyway.datasources.*.placeholder-prefix

java.lang.String

flyway.datasources.*.placeholder-suffix

java.lang.String

flyway.datasources.*.placeholder-separator

java.lang.String

flyway.datasources.*.script-placeholder-prefix

java.lang.String

flyway.datasources.*.script-placeholder-suffix

java.lang.String

flyway.datasources.*.sql-migration-prefix

java.lang.String

flyway.datasources.*.repeatable-sql-migration-prefix

java.lang.String

flyway.datasources.*.sql-migration-separator

java.lang.String

flyway.datasources.*.sql-migration-suffixes

java.lang.String

flyway.datasources.*.connect-retries

int

flyway.datasources.*.connect-retries-interval

int

flyway.datasources.*.init-sql

java.lang.String

flyway.datasources.*.baseline-description

java.lang.String

flyway.datasources.*.baseline-on-migrate

boolean

flyway.datasources.*.out-of-order

boolean

flyway.datasources.*.skip-executing-migrations

boolean

flyway.datasources.*.skip-default-callbacks

boolean

flyway.datasources.*.skip-default-resolvers

boolean

flyway.datasources.*.stream

boolean

flyway.datasources.*.batch

boolean

flyway.datasources.*.lock-retry-count

int

flyway.datasources.*.kerberos-config-file

java.lang.String

flyway.datasources.*.output-query-results

boolean

flyway.datasources.*.load-default-configuration-files

java.lang.String

flyway.datasources.*.create-schemas

boolean

flyway.datasources.*.fail-on-missing-locations

boolean

flyway.datasources.*.driver

java.lang.String

flyway.datasources.*.create-progress

java.lang.String

flyway.datasources.*.properties

java.util.Map

flyway.datasources.*.dry-run-output

java.lang.String

Sets the dry run output filename.

flyway.datasources.*.ignore-migration-patterns

java.lang.String

Sets the migration patterns to ignore.

flyway.datasources.*.locations

java.lang.String

Sets the locations to scan recursively for migrations.

flyway.datasources.*.encoding

java.lang.String

Sets the encoding of SQL migrations.

flyway.datasources.*.target

java.lang.String

Sets the target version up to which Flyway should consider migrations.

flyway.datasources.*.baseline-version

java.lang.String

The version to tag an existing schema with when executing baseline. Passes through to {@link FluentConfiguration#baselineVersion(String)}

By default Micronaut will configure Flyway to use the datasources defined under datasources configuration key. If you want to use a different datasource you need to define the properties flyway.datasources.*.url, flyway.datasources.*.user and flyway.datasources.*.password.

Flyway Configuration Parameters

You can set flyway configuration parameters. For example, you can setup PostgreSQL Transactional Lock:

flyway.datasources.default.properties.flyway.postgresql.transactional.lock=false
flyway:
  datasources:
    default:
      properties:
        flyway:
          postgresql:
            transactional:
              lock: false
[flyway]
  [flyway.datasources]
    [flyway.datasources.default]
      [flyway.datasources.default.properties]
        [flyway.datasources.default.properties.flyway]
          [flyway.datasources.default.properties.flyway.postgresql]
            [flyway.datasources.default.properties.flyway.postgresql.transactional]
              lock=false
flyway {
  datasources {
    'default' {
      properties {
        flyway {
          postgresql {
            transactional {
              lock = false
            }
          }
        }
      }
    }
  }
}
{
  flyway {
    datasources {
      default {
        properties {
          flyway {
            postgresql {
              transactional {
                lock = false
              }
            }
          }
        }
      }
    }
  }
}
{
  "flyway": {
    "datasources": {
      "default": {
        "properties": {
          "flyway": {
            "postgresql": {
              "transactional": {
                "lock": false
              }
            }
          }
        }
      }
    }
  }
}

Note that setting configuration this way will override any matching properties set via the known configuration keys in the tables above.

Configuring Custom Flyway Type Implementations

It is possible to inject implementations of certain Flyway type interfaces as beans. The following types are currently supported:

Type Description

JavaMigration[]

Java-based migrations.

Callback[]

Callbacks for lifecycle notifications.

MigrationResolver[]

MigrationResolvers to be used in addition to the built-in ones for resolving Migrations to apply.

ResourceProvider

ResourceProvider to be used to look up resources.

ClassProvider<JavaMigration>

ClassProvider to be used to look up JavaMigration classes.

The provided implementation must have a @Named qualifier that matches the name of the Flyway configuration name. For example, an array of JavaMigrations can be provided as in the following example:

@Factory
public class CustomFlywayTypesFactory {
    @Named("books")     (1)
    @Singleton
    public JavaMigration[] booksMigrations() {
        return [ new V3__Migrate_books() ];      (2)
    }

    static class V3__Migrate_books extends BaseJavaMigration    (3)
    {

        @Override
        void migrate(Context context) throws Exception {
            //Execute migration
        }
    }
}
1 The factory method has a @Named qualifier
2 A new JavaMigration instance is created
3 The returned class follows Flyway’s naming conventions for JavaMigrations

Customizing Flyway Configuration

Further customization of Flyway configuration can be done by providing a @Named implementation of FlywayConfigurationCustomizer. This allows you to directly set properties on Flyway’s FluentConfiguration builder before the migrations are executed. For example, you might want to set a property that is not yet supported in FlywayConfigurationProperties, or you might want to override a configuration value based on some runtime calculation.

@Singleton
public class BooksFlywayConfigurationCustomizer implements FlywayConfigurationCustomizer {  (1)

    private final static String NAME = "books";
    private final JavaMigration[] javaMigrations;

    public BooksFlywayConfigurationCustomizer(@Named(NAME) JavaMigration[] javaMigrations) { (2)
        this.javaMigrations = javaMigrations;
    }

    @Override
    public void customizeFluentConfiguration(FluentConfiguration fluentConfiguration) {
        if(javaMigrations != null) {
            fluentConfiguration.javaMigrations(javaMigrations); (3)
        }
    }

    @Override
    public String getName() {
        return NAME;
    }
}
1 The bean implements FlywayConfigurationCustomizer
2 A JavaMigration array is injected via a @Named qualifier
3 The migrations are set on the builder
Providing your own implementation of FlywayConfigurationCustomizer will override the default implementation which is used for the configuration of custom Flyway type implementations above. If you need to provide such types along with customizing the configuration, it must be done by your FlywayConfigurationCustomizer implementation. Your implementation may extend DefaultFlywayConfigurationCustomizer in order to retain the built-in behavior and augment it with further configuration adjustments of your own.

4 GraalVM support

Micronaut Flyway is compatible with GraalVM so it is possible to create native images and run the migrations during application startup.

The list of migrations to run is precomputed during native image build time and by default Micronaut looks for migrations in the Flyway default directory src/main/resources/db/migration. If you want to change that directory or add more directories to look for migrations you need to add an additional parameter to native-image command.

For example, if you have the following configuration:

flyway.datasources.default.locations[0]=classpath:databasemigrations
flyway.datasources.default.locations[1]=classpath:other
flyway:
  datasources:
    default:
      locations:
        - classpath:databasemigrations
        - classpath:other
[flyway]
  [flyway.datasources]
    [flyway.datasources.default]
      locations=[
        "classpath:databasemigrations",
        "classpath:other"
      ]
flyway {
  datasources {
    'default' {
      locations = ["classpath:databasemigrations", "classpath:other"]
    }
  }
}
{
  flyway {
    datasources {
      default {
        locations = ["classpath:databasemigrations", "classpath:other"]
      }
    }
  }
}
{
  "flyway": {
    "datasources": {
      "default": {
        "locations": ["classpath:databasemigrations", "classpath:other"]
      }
    }
  }
}
  • The locations properties configure Flyway to look for migrations in the directories src/main/resources/databasemigrations and src/main/resources/other.

You need to use the parameter flyway.locations with a comma separated list of directories to look for:

native-image --no-server --no-fallback \
    --class-path build/libs/micronaut-flyway-graal-*-all.jar \
    -Dflyway.locations='classpath:databasemigrations,classpath:other' (1)
1 Define the locations to look for migrations.
See the section on GraalVM in the user guide for more information.

5 Events

Micronaut fires two different events when:

6 Endpoint

This configuration also provides a built-in endpoint to expose all the applied migrations in /flyway.

To enable the endpoint add the following to the configuration:

resources/application.yml
endpoints.flyway.enabled=true
endpoints.flyway.sensitive=false
endpoints:
  flyway:
    enabled: true
    sensitive: false
[endpoints]
  [endpoints.flyway]
    enabled=true
    sensitive=false
endpoints {
  flyway {
    enabled = true
    sensitive = false
  }
}
{
  endpoints {
    flyway {
      enabled = true
      sensitive = false
    }
  }
}
{
  "endpoints": {
    "flyway": {
      "enabled": true,
      "sensitive": false
    }
  }
}
  • /flyway endpoint is enabled (this is the default) and open for unauthenticated access.

$ curl http://localhost:8080/flyway

[{
    "name": "default",
    "migrations": [{
        "checksum": 1952043475,
        "installedOn": "2018-11-12T11:32:52.000+0000",
        "executionTime": 96,
        "installedRank": 1,
        "version": {
            "version": "1"
        },
        "description": "init",
        "installedBy": "root",
        "state": "SUCCESS",
        "type": "SQL",
        "script": "V1__init.sql"
    }, {
        "checksum": -1926058189,
        "installedOn": "2018-11-12T11:32:52.000+0000",
        "executionTime": 10,
        "installedRank": 2,
        "version": {
            "version": "2"
        },
        "description": "testdata",
        "installedBy": "root",
        "state": "SUCCESS",
        "type": "SQL",
        "script": "V2__testdata.sql"
    }]
}]
See the section on Built-in endpoints in the user guide for more information.

7 Guides

See the guide for Schema Migration With Flyway to learn more.

8 Repository

You can find the source code of this project in this repository: