すでに本番で動いているデータベースに、今からFlywayを導入したいというケースはよくありますよね。新規プロジェクトならV1からマイグレーションを書いていけば済みますが、既存テーブルがすでに存在する環境だと話が変わってきます。
この記事では、baseline-on-migrate を中心に、すでにデータが入っている既存DBへFlywayを安全に後付けする手順に絞って解説します。Flyway自体の基本概念や新規導入手順はSpring BootでFlywayを使ったデータベースマイグレーション管理で扱っているので、そちらを先に読んでおくとスムーズです。checksum不一致の復旧はFlywayのchecksum mismatch対処ガイドを参照してください。
こんな場面でbaselineOnMigrateが必要になる
典型的なのは、users や orders などのテーブルがすでに本番で稼働していて、flyway_schema_history テーブルはまだ存在しない、という状況です。Flywayを依存に追加しただけで何もマイグレーションを書いていない状態ですね。
この状態でいきなりFlywayを有効化すると、Flywayは「まだ何も適用されていない」と判断し V1__init.sql のようなスクリプトを実行しようとします。しかし対象のテーブルはすでに存在するので、CREATE TABLE が重複エラーで失敗し、アプリケーションが起動しなくなります。
新規プロジェクトでのFlyway導入(何もないDBにV1を適用する)とは前提が違います。既存DBへの後付けでは、「今あるテーブル構造をどこかのバージョンとして認識させる」一手間が必要で、それが baseline-on-migrate の役割です。
baselineOnMigrate・baselineVersion・baseline-descriptionの設定
application.yml に次のように設定します。
spring:
flyway:
baseline-on-migrate: true
baseline-version: 1
baseline-description: "既存スキーマ (2026-10導入前の状態)"
baseline-on-migrate=true にすると、flyway_schema_history が存在しない場合だけbaseline処理が走ります。すでに履歴テーブルがある環境では何も起きないので、新規・既存どちらの環境にも同じ設定を使えます。
baseline-version は既存スキーマをどのバージョンとして扱うかの指定で、デフォルトは 1 です。これから追加する最初のマイグレーションは、このバージョンより大きい番号にする必要があります。baseline-version=1 なら V2__add_email_column.sql から始める形です。
baseline-description は省略可能で、省略時のデフォルト値は << Flyway Baseline >> になります。日付やチケット番号を含めて明示しておくと、後から履歴を見た人が状況を把握しやすくなります。これらのプロパティはSpring Boot 2系以降で標準サポートされています。
Gradle/Mavenプラグインには別途設定が必要
application.yml の spring.flyway.* は、Spring Bootが起動時に自動構成するFlywayインスタンスにしか渡りません。本番適用前のドライラン確認で使うGradleプラグインの flywayInfo タスクは、Spring Bootのコンテキストとは無関係に単独で動くため、spring.flyway.* を読み込みません。
そのため build.gradle 側にも接続情報とbaseline設定を別途書く必要があります。
flyway {
url = 'jdbc:mysql://localhost:3306/shop_db'
user = 'app_user'
password = System.getenv('DB_PASSWORD')
baselineOnMigrate = true
baselineVersion = '1'
baselineDescription = '既存スキーマ (2026-10導入前)'
}
Mavenなら pom.xml の flyway-maven-plugin の <configuration> に同じ項目を書きます。これを忘れると flywayInfo が接続先を見つけられずエラーになります。
flyway infoで本番適用前にドライラン確認する
Gradleプラグインの設定が済んだら、適用前に状態を確認します。
./gradlew flywayInfo
Version | Description | Type | State
1 | 既存スキーマ (2026-10導入前) | BASELINE | Pending
2 | add email column | SQL | Pending
flyway info は読み取り専用で、スキーマには何も書き込みません。想定外のスクリプトが Pending に出てきたら、flyway migrate を実行する前に中身を確認してください。
flyway_schema_historyに作られる最初のbaselineマーカー行
baseline-on-migrate が走ると、flyway_schema_history に次の1行が追加されます。
SELECT version, description, type, success
FROM flyway_schema_history ORDER BY installed_rank;
version | description | type | success
1 | 既存スキーマ (2026-10導入前) | BASELINE | 1
2 | add email column | SQL | 1
type が BASELINE の行がマーカーです。実際にSQLを実行したわけではなく、「ここまでは適用済み」という印だけが記録されます。以降Flywayはこの行より新しいバージョンだけを適用対象として扱い、V1はbaseline、実際に実行されるのはV2からになります。
ステージング環境で検証する
本番に適用する前に、必ずステージングで試しておきます。まずスキーマだけを本番からダンプしてリストアします。
mysqldump -u app_user -p --no-data shop_db > schema.sql
mysql -u app_user -p shop_db_staging < schema.sql
ステージング用の設定ファイルにも同じ値を書き、アプリケーションを起動して flyway_schema_history にbaseline行が1件だけ作られることを確認します。その後マイグレーションを1本追加し、V2以降が正しく適用されることまで確認できれば、同じ設定を本番用Profileに適用して問題ありません。MySQL接続自体の設定が不安な場合はSpring BootでMySQLに接続するapplication.yml設定も確認しておくと安心です。
baselineVersionを誤ると起きる典型的な失敗
よくあるのは、baseline-version を実際のマイグレーションバージョンと同じか、それより大きくしてしまうケースです。baseline-version=2 なのに V2__add_email_column.sql を用意すると、FlywayはV2をbaseline済みとみなしてスキップしてしまい、意図した変更が反映されません。
もう一つは baseline-on-migrate=false(デフォルト)のまま既存DBに適用してしまうケースです。履歴テーブルが存在しない状態で最初のマイグレーションを実行しようとし、既存テーブルとの重複エラーで起動に失敗します。
org.flywaydb.core.api.FlywayException: Found non-empty schema(s) "shop_db" but no schema history table.
このエラーが出たら、baseline-on-migrate が true か、baseline-version が既存スクリプトと衝突していないかを確認してください。
まとめ 新規導入とbaseline導入の違いを整理する
新規プロジェクトでのFlyway導入は、何もないDBにV1から適用していくシンプルな話です。一方、稼働中のテーブルがある既存DBへの後付け導入は、baseline-on-migrate で「今の状態をどこかのバージョンとして認識させる」一手間が必要になります。
baseline-version と baseline-description を設定し、GradleやMavenのプラグイン側にも同じ接続情報とbaseline設定を書いた上で flyway info でPendingの内容を確認し、ステージングで一度試してから本番に反映すれば、既存テーブルを壊すリスクはかなり抑えられます。
導入後にchecksum不一致のエラーに遭遇した場合は、Flywayのchecksum mismatch対処ガイドを参照してください。