Using Flyway for MongoDB schema migrations
| This extension is experimental. Its configuration and API may change between releases. |
This extension applies Flyway migrations to MongoDB
databases that are configured through the
Quarkus MongoDB client extension. It wraps Flyway’s
community-edition flyway-database-nc-mongodb connector, which uses the
official MongoDB Java driver for schema-history operations and the
mongosh shell to execute
the JavaScript migration scripts.
Prerequisites
The flyway-database-nc-mongodb connector executes JavaScript (.js)
migration scripts by spawning a mongosh subprocess, so when you use
.js migrations mongosh must be installed and available on the PATH
of the process that runs Flyway. This is true at both development time and
at runtime (including JVM and native modes).
Install mongosh by following the
official instructions
for your operating system.
If mongosh is not available, Flyway will fail when applying a .js
migration with an error from the NC connector indicating that the shell
could not be started.
mongosh is not required if you use JSON (.json) migrations, which are
executed directly through the MongoDB driver API. Set
quarkus.flyway-mongodb.migration-suffixes=.json to switch to that format
(see Migration scripts).
Installation
To use this extension, add the io.quarkiverse.mongodb:quarkus-flyway-mongodb dependency to your build file.
With Maven, add the following to your pom.xml:
<dependency>
<groupId>io.quarkiverse.mongodb</groupId>
<artifactId>quarkus-flyway-mongodb</artifactId>
<version>0.1.0</version>
</dependency>
With Gradle, add the following to your build.gradle:
implementation("io.quarkiverse.mongodb:quarkus-flyway-mongodb:0.1.0")
quarkus-mongodb-client is pulled in transitively. Configure your MongoDB
client as you normally would.
Configuration
Migrations are scanned at build time from db/migration (configurable).
For each MongoDB client configured under quarkus.mongodb.*, the extension
produces a Flyway and FlywayMongodbContainer bean.
quarkus.mongodb.connection-string=mongodb://localhost:27017
quarkus.mongodb.database=app
quarkus.flyway-mongodb.database=app
quarkus.flyway-mongodb.migrate-at-start=true
With quarkus.flyway-mongodb.migrate-at-start=true, as in the example
above, Quarkus will execute the Flyway migration as part of the
application startup.
|
To target a named MongoDB client, repeat the per-client subkeys:
quarkus.mongodb.analytics.connection-string=mongodb://localhost:27017
quarkus.mongodb.analytics.database=analytics
quarkus.flyway-mongodb.analytics.database=analytics
quarkus.flyway-mongodb.analytics.locations=analytics-migrations
quarkus.flyway-mongodb.analytics.migrate-at-start=true
Inject the named instance with the @FlywayMongodbClient qualifier:
import io.quarkiverse.mongodb.flyway.FlywayMongodbClient;
import org.flywaydb.core.Flyway;
import jakarta.inject.Inject;
public class AnalyticsService {
@Inject
@FlywayMongodbClient("analytics")
Flyway flyway;
}
Without explicit quarkus.flyway-mongodb.* configuration, a Flyway
bean is still produced for every configured MongoDB client using the default
settings. Startup operations such as migrate-at-start remain disabled until
opted in.
|
Migration scripts
Migrations follow Flyway’s naming convention, for example V1__create_users.js.
By default only .js files are scanned. JavaScript migrations are executed
via mongosh; the flyway-database-nc-mongodb connector also accepts
.json migrations, which are executed through the MongoDB driver API.
However, the connector does
not
currently support mixing .js and .json migrations in the same Flyway project — pick
one format and configure migration-suffixes accordingly:
# use JSON-format migrations instead of JavaScript (build-time property)
quarkus.flyway-mongodb.migration-suffixes=.json
db.createCollection("users");
db.users.insertOne({ name: "alice" });
In dev mode Quarkus will automatically restart the application if any of
the existing migration scripts get modified. If you want to take advantage of
this while developing and testing new migration scripts, you will want to set
%dev.quarkus.flyway-mongodb.clean-at-start=true, so that Flyway actually
runs the modified migration.
|
Programmatic configuration customization
Implement FlywayMongodbConfigurationCustomizer as a CDI bean to customize
Flyway’s FluentConfiguration before the Flyway instance is created:
import io.quarkiverse.mongodb.flyway.FlywayMongodbConfigurationCustomizer;
import jakarta.enterprise.context.ApplicationScoped;
import org.flywaydb.core.api.configuration.FluentConfiguration;
@ApplicationScoped
public class MyFlywayCustomizer implements FlywayMongodbConfigurationCustomizer {
@Override
public void customize(FluentConfiguration configuration) {
configuration.encoding("UTF-8");
}
}
To target a specific named client, add the @FlywayMongodbClient qualifier:
@ApplicationScoped
@FlywayMongodbClient("analytics")
public class AnalyticsFlywayCustomizer implements FlywayMongodbConfigurationCustomizer {
@Override
public void customize(FluentConfiguration configuration) {
configuration.outOfOrder(true);
}
}
Using the Flyway object
In case you are interested in using the Flyway object directly, you can
inject it as follows:
import io.quarkiverse.mongodb.flyway.FlywayMongodbClient;
import org.flywaydb.core.Flyway;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
@ApplicationScoped
public class MigrationService {
@Inject
Flyway flyway; (1)
@Inject
@FlywayMongodbClient("inventory") (2)
Flyway flywayForInventory;
public void checkMigration() {
// Use the Flyway instance manually
flyway.clean(); (3)
flyway.migrate();
// This will print the current schema version, e.g. 1.0.0
System.out.println(flyway.info().current().getVersion().toString());
}
}
| 1 | Inject the Flyway object for the default MongoDB client. |
| 2 | Inject Flyway for a named MongoDB client using the FlywayMongodbClient qualifier. |
| 3 | Use the Flyway instance directly. Calling clean() requires clean-disabled=false. |
Startup operations
The following per-client flags control startup behavior. Operations run
in this order: clean → validate → baseline → repair → migrate.
| Property | Default | Description |
|---|---|---|
|
unset |
Activate/deactivate Flyway for this client at runtime. When |
|
|
Run |
|
unset |
Run |
|
|
Run |
|
|
Run |
|
|
Run |
|
|
Flyway safety lock. When true, |
|
|
If validation fails, automatically clean before migrate. |
|
|
Pass-through to Flyway’s |
|
unset |
Pass-through. |
|
unset |
Pass-through. |
|
|
Schema history collection name. |
|
empty |
Placeholder substitutions for migration scripts. |
The following property is evaluated at build time:
| Property | Default | Description |
|---|---|---|
|
|
File suffixes used when scanning for migration scripts. Changes require an application rebuild. |
The tables above cover the most user-facing properties. Additional
per-client knobs such as connect-retries, connect-retries-interval,
connection-string, database, migration-prefix,
repeatable-migration-prefix, placeholder-prefix, placeholder-suffix,
validate-on-migrate, validate-migration-naming, out-of-order,
ignore-missing-migrations, ignore-future-migrations, and
ignore-migration-patterns are also supported. The full reference is
generated below.
Repairing the Flyway schema history collection
There are scenarios that may require repairing the Flyway schema history
collection — for example, when a migration script fails partway through and
leaves the flyway_schema_history collection in an inconsistent state.
In such situations the Flyway repair command comes in handy. In Quarkus this can either be executed automatically before the migration by setting quarkus.flyway-mongodb.repair-at-start=true or manually by injecting the Flyway object and calling Flyway#repair().
Flyway MongoDB and reactive MongoDB clients
Flyway MongoDB always drives migrations through the official MongoDB Java
driver and the mongosh shell (see the Prerequisites), regardless of how
the application accesses MongoDB at runtime. The Quarkus MongoDB client can
be consumed via either the blocking MongoClient API or the reactive
ReactiveMongoClient API — both are wired from the same
quarkus.mongodb.* configuration, and no additional setup is required to
use Flyway MongoDB with a reactive application.
Flyway on Kubernetes
Sometimes it’s helpful not to execute Flyway initialization on each application
startup. One such example is when deploying on Kubernetes, where it doesn’t
make sense to execute Flyway on every single replica. Instead it’s desirable
to execute it once and then start the actual application without Flyway. To
support this use case, when generating manifests for Kubernetes the generated
manifests contain a Kubernetes initialization Job for Flyway MongoDB.
The Job runs the migrations once and the application Pod starts only
after the Job completes successfully.
Disabling
The feature is enabled by default and can be globally disabled, using:
quarkus.kubernetes.init-task-defaults.enabled=false
or on OpenShift:
quarkus.openshift.init-task-defaults.enabled=false
Using a custom image that controls waiting for the Job
To change the wait-for image which by default is groundnuty/k8s-wait-for:no-root-v1.7 you can use:
quarkus.kubernetes.init-task-defaults.wait-for-container.image=my/wait-for-image:1.0
or on OpenShift:
quarkus.openshift.init-task-defaults.wait-for-container.image=my/wait-for-image:1.0
Note: In this context globally means for all extensions that support init task externalization.
Dev UI
When the application runs in dev mode, the extension contributes a card to the Dev UI that lists every configured MongoDB client managed by Flyway, along with:
-
the number of pending and applied migrations,
-
the current schema-history version,
-
the resolved migration locations,
-
whether
cleanis disabled.
The card also exposes per-client Migrate and Clean actions, which invoke
flyway.migrate() and flyway.clean() respectively against the running
application. The Clean action is disabled when clean-disabled is true.
Limitations
-
Only script-based migrations are supported (no Java migrations).
-
Java
Callbackbeans are not wired into theFlywayinstance. Script-based callbacks placed in the configured migration locations are, however, picked up by Flyway and executed. The supported lifecycle event prefixes (used as<event>__<description>.js) are:-
Migrate:
beforeMigrate,afterMigrate,afterMigrateError,beforeEachMigrate,afterEachMigrate,afterEachMigrateError -
Clean:
beforeClean,afterClean,afterCleanError -
Baseline:
beforeBaseline,afterBaseline,afterBaselineError -
Validate:
beforeValidate,afterValidate,afterValidateError -
Repair:
beforeRepair,afterRepair,afterRepairError -
Info:
beforeInfo,afterInfo,afterInfoError
Statement-level callbacks (
beforeEachMigrateStatement,afterEachMigrateStatement, …) are a SQL-parser feature and do not apply, since each.jsmigration is executed as a singlemongoshinvocation. Undo callbacks are Flyway Teams-only and are not available. ThecreateSchemacallback is a JDBC-layer event and is never fired against MongoDB, which has no schema-creation step. -
-
The extension wraps the community-edition
flyway-database-nc-mongodbconnector. Flyway’s commercialflyway-database-mongodb(Teams) is not used. -
MongoDB with Panache is not ordered after the migrations, so Panache may start before the migrations at startup have finished. This ordering will be added once the extension moves to a Quarkus release that includes quarkusio/quarkus#57204.
Configuration Reference
See the Configuration Reference for all quarkus.flyway-mongodb.* properties.