✅ Short Answer
Yes, you can write migrations in Java by implementing the JavaMigration interface or extending BaseJavaMigration.
This allows you to write complex, logic-driven database changes in code, including loops, conditional logic, or calling other APIs.
🔍 How to Write a Java-Based Migration
✅ Step 1: Create a class like this:
import org.flywaydb.core.api.migration.BaseJavaMigration;
import org.flywaydb.core.api.migration.Context;
public class V3__Add_default_users extends BaseJavaMigration {
@Override
public void migrate(Context context) throws Exception {
try (var statement = context.getConnection().createStatement()) {
statement.execute("INSERT INTO users (name, email) VALUES ('admin', 'admin@example.com')");
}
}
}
✅ Step 2: Place the file in:
src/main/java/db/migration/
📦 By default, Flyway scans this package:
db.migration
🧠 Java Migration Naming Convention
| Type | Naming Format |
|---|---|
| Versioned | V3__Add_default_users.java |
| Repeatable | R__Seed_data.java |
Same naming rules apply as for SQL files.
✅ When to Use Java Migrations
| Use Case | Why Java Helps |
|---|---|
| Conditional logic | Handle “if exists” / “if not” programmatically |
| Complex data transformations | Java gives more control than plain SQL |
| Interacting with external systems | API calls, config checks, auditing |
| Platform-agnostic logic | Avoid SQL dialect issues |
⚠️ Limitations
- No support for undo migrations in Java
- You still need to track the version and description manually in the class name
- Slightly more setup effort than SQL
📌 Key Takeaways
✅ Flyway supports Java-based migrations for advanced, logic-heavy use cases
✅ Use BaseJavaMigration to create versioned migrations in Java
✅ Name your classes like V2__Description.java and place them under db.migration
✅ Ideal when SQL is not expressive or safe enough for your migration logic