Flyway は、DB のテーブル変更を「番号付きの SQL ファイル」で管理し、まだ流していないものだけを順に実行するツールです。 Spring Boot では、src/main/resources/db/migration に V1__create_users.sql のようなファイルを置くと、アプリの起動時に自動で流れます。どこまで流したかは、DB の中の flyway_schema_history という表に記録されます。

Spring Boot 4 からは、flyway-core だけでは自動実行されません。spring-boot-starter-flyway を入れます。 PostgreSQL や MySQL では、DB ごとのモジュール(flyway-database-postgresql など)も要ります。

よくあるエラー(原文の先頭) 原因 直し方
Migration checksum mismatch for migration version 1 流し終えた SQL ファイルを書き換えた 元に戻す。意図した変更なら repair
Detected failed migration to version 3 前回の実行が途中で失敗し、失敗の記録が残っている 途中まで変わった部分を手で戻し、repair してから流し直す
Detected resolved migration not applied to database: 2.5. 適用済みの版より小さい版のファイルを後から足した 版番号を振り直す。どうしても要るなら outOfOrder=true
Detected applied migration not resolved locally: 2.5. 適用済みのファイルを消した ファイルを戻す。意図して消したなら repair
Found non-empty schema(s) "public" but no schema history table. 既存の DB に初めて Flyway を入れた baselineOnMigrate=true(Boot は spring.flyway.baseline-on-migrate)
No Flyway database plugin found to handle jdbc:postgresql://… DB ごとのモジュールが無い flyway-database-postgresql を足す

確認環境:Spring Boot 4.1.1(GitHub のリリースで最新の安定版)が管理する Flyway 12.4.0 と、PostgreSQL 16.15・OpenJDK 21.0.10(Linux)。Flyway は GitHub のタグ flyway-12.4.0 のソースからビルドした Java API(Flyway.configure()…migrate())で動かし、この記事のエラー文とログはその出力です。Spring Boot 側の設定名・既定値は、タグ v4.1.1 のソースの FlywayProperties(設定クラス)と、Spring Boot のドキュメント・4.0 移行ガイドで確かめました。Flyway 単体の最新版は 13.10.0 です(確認日 2026年10月13日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Flywayの使い方|Spring Boot・命名規則・失敗時の直し方」

Flyway のしくみ:3つの言葉

言葉 意味
マイグレーション DB の変更を書いた1つのファイル(V1__create_users.sql など)。一度流したら書き換えない
スキーマ履歴表(flyway_schema_history) どのファイルを、いつ、成功したか、チェックサム(中身から計算した数値)は何か、を記録する表
チェックサム ファイルの中身から計算した値。流した後に中身が変わると、記録とずれてエラーになる

migrate(流す)を呼ぶと、Flyway は次の順に動きます。

  1. flyway_schema_history が無ければ作る
  2. validate:適用済みのファイルが書き換えられていないか、チェックサムを比べる
  3. まだ流していない版(Pending)を、版番号の小さい順に流す
  4. 中身が変わった繰り返し用(R__)のファイルを流す
  5. 1ファイルごとに、結果を flyway_schema_history に記録する

ファイル名の規則(早見表)

形は 接頭辞 + 版 + __(アンダースコア2つ)+ 説明 + .sql です。 Flyway のドキュメントでは「prefixVERSIONseparatorDESCRIPTIONsuffix」と書かれ、既定値では V1.1__My_description.sql になります。

接頭辞 種類 例 いつ流れるか
V 版付き(Versioned) V1__create_users.sql 1回だけ。版の小さい順
R 繰り返し(Repeatable) R__users_view.sql 中身が変わるたび。版付きの後に、説明の順
B ベースライン(Baseline) B2__baseline.sql 新しい DB でだけ。それ以下の版を飛ばす
U 取り消し(Undo) U3__drop_orders.sql undo コマンドのとき。Flyway Teams(有料版)の機能

版と説明の書き方

書き方 結果(Flyway 12.4.0 の info)
V1.1__b.sql と V1_2__c.sql 版は 1.1・1.2。版の中の _ は . と同じ扱い
V2__d.sql と V10__e.sql 1 → 2 → 10 の順。文字列ではなく数値で並ぶ
V2026.10.12.1__f.sql 版は 2026.10.12.1。日付を版にする書き方もできる
V01__dup.sql と V1__a.sql Found more than one migration with version 01。先頭の0は無視され、同じ版になる
V3__dup.sql と V3__create_orders.sql Found more than one migration with version 3 で止まる
V4_add_index.sql(_ が1つ) エラーにならず黙って無視された(下の囲み)
v5__lower.sql(小文字の v) これも無視された
説明の _ 表示では空白になる(create_users → create users)

区切りを _ 1つにすると、エラーにならずに無視されます。 ログには次の2行が出るだけでした。

INFO: 1 SQL migrations were detected but not run because they did not follow the filename convention.
INFO: Set 'validateMigrationNaming' to true to fail fast and see a list of the invalid file names.

validateMigrationNaming を true にすると、起動時に止まって、ファイル名を教えてくれます。

org.flywaydb.core.api.FlywayException: Invalid SQL filenames found:
Invalid versioned migration name format: V4_add_index.sql (could not recognise version number 4_add_index)

Spring Boot では spring.flyway.validate-migration-naming=true を入れておくと、名前の書き間違いに早く気づけます。

B(ベースライン)は、ビルドした Flyway 12.4.0(オープンソース版)で動きました。V1・V2・B2・V3 を置いた空の DB では、B2 と V3 だけが流れ、V1 は Below Baseline、V2 は Ignored (Baseline) になりました。U3__undo.sql は、上と同じ「名前の規則に合わないファイル」として数えられ、流れませんでした。

テーブル名やインデックス名の付け方は、関連記事「DB命名規則一覧|テーブル名・カラム名・インデックス名・制約名」で扱っています。

Spring Boot 4 での導入

Boot 4 で変わった依存

Spring Boot 4.0 の移行ガイドには、「Flyway や Liquibase は、以前は第三者の依存(flyway-core)だけを入れていた。spring-boot-starter-flyway に切り替える」という趣旨が書かれています。Boot 4 では自動設定が spring-boot-flyway というモジュールに分かれたため、starter(必要なものをまとめた依存)を入れないと、起動時に流れません。

Boot 3 まで Boot 4
Flyway 本体 org.flywaydb:flyway-core org.springframework.boot:spring-boot-starter-flyway
PostgreSQL flyway-database-postgresql 同じ(flyway-database-postgresql)
MySQL flyway-mysql 同じ(flyway-mysql)
テスト用 spring-boot-starter-test spring-boot-starter-flyway-test(spring-boot-starter-test も一緒に入る)
管理される版(4.1.1) — Flyway 12.4.0

Boot のドキュメントでは、「インメモリやファイルの DB(H2 など)は starter だけで動く。それ以外は DB ごとのモジュールも要る」とあり、例として flyway-database-postgresql と flyway-mysql が挙がっています。

Boot 4 の starter の名前の変更は、関連記事「Spring Boot starter一覧|用途別の選び方とBoot 4の新旧対応表」で、移行の全体は、関連記事「Spring Boot 4移行の手順|3から4の変更点一覧とチェックリスト」で扱っています。

build.gradle.kts

plugins {
    java
    id("org.springframework.boot") version "4.1.1"
    id("io.spring.dependency-management") version "1.1.7"
}

java { toolchain { languageVersion = JavaLanguageVersion.of(21) } }

repositories { mavenCentral() }

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-webmvc")
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    implementation("org.springframework.boot:spring-boot-starter-flyway")   // Boot 4 はこれ
    implementation("org.flywaydb:flyway-database-postgresql")               // PostgreSQL 用
    runtimeOnly("org.postgresql:postgresql")

    testImplementation("org.springframework.boot:spring-boot-starter-flyway-test")
    testImplementation("org.springframework.boot:spring-boot-starter-data-jpa-test")
}

tasks.test { useJUnitPlatform() }

pom.xml(dependencies の部分)

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>4.1.1</version>
</parent>

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-flyway</artifactId>
  </dependency>
  <dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-database-postgresql</artifactId>
  </dependency>
  <dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <scope>runtime</scope>
  </dependency>
</dependencies>

版は親(spring-boot-starter-parent)が決めるので、<version> は書きません。Gradle の書き方の対訳は、関連記事「build.gradle書き方|Groovy/Kotlin DSL対訳と依存設定一覧」で扱っています。

フォルダとファイル

src/main/resources/
├── application.yml
└── db/migration/
    ├── V1__create_users.sql
    ├── V2__add_email_to_users.sql
    └── R__users_view.sql
-- V1__create_users.sql
CREATE TABLE users (
  id   BIGSERIAL PRIMARY KEY,
  name VARCHAR(100) NOT NULL
);
-- V2__add_email_to_users.sql
ALTER TABLE users ADD COLUMN email VARCHAR(255);
-- R__users_view.sql(中身が変わるたびに流れる)
CREATE OR REPLACE VIEW v_users AS SELECT id, name FROM users;

application.yml

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/app
    username: app
    password: ${DB_PASSWORD}
  jpa:
    hibernate:
      ddl-auto: validate          # テーブルは Flyway が作る。JPA は照合だけ
  flyway:
    enabled: true
    locations: classpath:db/migration
    validate-migration-naming: true   # 名前の書き間違いで止める

ddl-auto は validate か none にします。 update のままだと、Hibernate(JPA)と Flyway の両方がテーブルを変えようとします。Boot のドキュメントでも、Flyway を使うときに schema.sql・data.sql を一緒に使うことはすすめられていません。

実行結果(初回)

3つのファイルを空の DB に流したときのログです。

INFO: Database: jdbc:postgresql://127.0.0.1:55439/demo (PostgreSQL 16.15)
INFO: Schema history table "public"."flyway_schema_history" does not exist yet
INFO: Successfully validated 3 migrations (execution time 00:00.047s)
INFO: Creating Schema History table "public"."flyway_schema_history" ...
INFO: Current version of schema "public": << Empty Schema >>
INFO: Migrating schema "public" to version "1 - create users"
INFO: Migrating schema "public" to version "2 - add email to users"
INFO: Migrating schema "public" with repeatable migration "users view"
INFO: Successfully applied 3 migrations to schema "public", now at version v2 (execution time 00:00.015s)

flyway_schema_history の中身です。

 installed_rank | version |    description     | type |           script           |  checksum   | success
----------------+---------+--------------------+------+----------------------------+-------------+---------
              1 | 1       | create users       | SQL  | V1__create_users.sql       | -1198624226 | t
              2 | 2       | add email to users | SQL  | V2__add_email_to_users.sql |  -789335033 | t
              3 |         | users view         | SQL  | R__users_view.sql          | -2128053619 | t

R__users_view.sql の中身を変えて流すと、そのファイルだけがもう一度流れ、前の記録は Superseded(置き換え済み)になりました。

Repeatable   users view   SQL   Superseded  -2128053619
Repeatable   users view   SQL   Success     -1765499091

spring.flyway.* 設定一覧(Boot 4.1.1)

Spring Boot 4.1.1 のソースの FlywayProperties(@ConfigurationProperties("spring.flyway"))から、よく使うものを並べました。既定値はソースの初期値です。

基本

設定 既定値 意味
spring.flyway.enabled true Flyway を動かすか
spring.flyway.locations classpath:db/migration SQL を探す場所。filesystem: も可。{vendor} で DB ごとに分けられる
spring.flyway.fail-on-missing-locations false 場所が無いとき止めるか
spring.flyway.encoding UTF-8 SQL ファイルの文字コード
spring.flyway.default-schema なし Flyway が管理する既定のスキーマ
spring.flyway.schemas なし 管理するスキーマの一覧
spring.flyway.create-schemas true schemas のスキーマを作るか
spring.flyway.table flyway_schema_history 履歴表の名前
spring.flyway.target latest どの版まで流すか
spring.flyway.url・user・password なし Flyway 専用の接続。無ければ spring.datasource.* を使う

検証・順序・ベースライン

設定 既定値 意味
spring.flyway.validate-on-migrate true 流す前にチェックサムなどを確かめるか
spring.flyway.validate-migration-naming false 名前の規則に合わないファイルで止めるか
spring.flyway.ignore-migration-patterns *:future 検証で無視する状態(例:*:missing)
spring.flyway.out-of-order false 小さい版を後から流すのを許すか
spring.flyway.baseline-on-migrate false 履歴表の無い既存 DB で、自動で baseline するか
spring.flyway.baseline-version 1 baseline で付ける版
spring.flyway.baseline-description << Flyway Baseline >> baseline の説明
spring.flyway.clean-disabled true clean(全部消す)を禁止するか

ファイル名・プレースホルダー

設定 既定値 意味
spring.flyway.sql-migration-prefix V 版付きの接頭辞
spring.flyway.repeatable-sql-migration-prefix R 繰り返しの接頭辞
spring.flyway.sql-migration-separator __ 区切り
spring.flyway.sql-migration-suffixes .sql 拡張子
spring.flyway.placeholders.* なし SQL の中の ${名前} を置き換える値
spring.flyway.placeholder-replacement true 置き換えをするか
spring.flyway.placeholder-prefix・-suffix ${・} プレースホルダーの囲み

実行のしかた・接続

設定 既定値 意味
spring.flyway.execute-in-transaction true SQL をトランザクションの中で流すか
spring.flyway.group false 未適用の全ファイルを1つのトランザクションにまとめるか
spring.flyway.mixed false 1ファイルにトランザクション可・不可の文を混ぜるのを許すか
spring.flyway.connect-retries 0 DB に繋がらないときの再試行回数
spring.flyway.connect-retries-interval 120(秒) 再試行の最大の間隔
spring.flyway.lock-retry-count 50 ロックを取る再試行回数
spring.flyway.init-sqls なし 接続直後に流す SQL
spring.flyway.installed-by なし 履歴表に記録する実行ユーザー名
spring.flyway.postgresql.transactional-lock Flyway の既定(true) PostgreSQL のロックをトランザクション単位にするか

この他に、callback-locations・skip-default-callbacks・loggers(既定 slf4j)などがあります。dry-run-output や oracle.sqlplus などは、ソースのコメントに「Requires Flyway Teams」とある有料版向けです。

Boot の設定ファイル全般は、関連記事「Spring Boot application.properties設定一覧」で、環境ごとの切り替えは、関連記事「Spring Bootプロファイル切り替え|application.ymlと優先順位」で扱っています。

失敗したときの直し方

ここからは、実際にエラーを起こして、原文と直し方を確かめた結果です。

① Migration checksum mismatch(流した後に書き換えた)

流し終えた V1__create_users.sql の VARCHAR(100) を VARCHAR(200) に書き換えて起動すると、次のエラーで止まりました。

org.flywaydb.core.api.exception.FlywayValidateException: Validate failed: Migrations have failed validation
Migration checksum mismatch for migration version 1
-> Applied to database : -1198624226
-> Resolved locally    : -1443686297
Either revert the changes to the migration, or run repair to update the schema history.

Applied to database は履歴表に記録された値、Resolved locally は今のファイルから計算した値です。

状況 直し方
間違って書き換えた ファイルを元に戻す(git で戻すのが確実)
コメントや空白だけを直した repair で記録のチェックサムを今のファイルに合わせる
テーブルの形を変えたい 元のファイルは戻し、新しい版(V3__…)で ALTER TABLE を書く

repair を実行したときのログです。DB のテーブルは変わらず、履歴表のチェックサムだけが書き換わりました。

INFO: Repair of failed migration in Schema History table "public"."flyway_schema_history" not necessary. No failed migration detected.
INFO: Repairing Schema History table for version 1 (Description: create users, Type: SQL, Checksum: -1443686297)  ...
INFO: Successfully repaired schema history table "public"."flyway_schema_history" (execution time 00:00.109s).

repair で合わせても、すでに作られたテーブルは VARCHAR(100) のままです。 書き換えた中身は、新しく作る DB にしか効きません。環境ごとに形がずれるので、形の変更は新しい版で書きます。カラムの追加や型の変更の SQL は、関連記事「ALTER TABLEでカラム追加・型変更|MySQL・PostgreSQL比較」で扱っています。

② SQL の誤りで失敗した(PostgreSQL では全部戻る)

V3__create_orders.sql の最後の行を ADD COLUM(N が抜けた)にして流しました。

SEVERE: Migration of schema "public" to version "3 - create orders" failed! Changes successfully rolled back.
org.flywaydb.core.internal.exception.FlywayMigrateException: Failed to execute script V3__create_orders.sql
----------------------------------------------
SQL State  : 42601
Error Code : 0
Message    : ERROR: syntax error at or near "TEXT"
  Position: 35
Location   : src/main/resources/db/migration/V3__create_orders.sql (…/V3__create_orders.sql)
Line       : 6
Statement  : Run Flyway with -X option to see the actual statement causing the problem

PostgreSQL は DDL(CREATE TABLE など)もトランザクションで戻せるので、1行目の CREATE TABLE orders も取り消され、orders 表は残っていませんでした。 履歴表にも記録されず、V3 は Pending(未適用)のままです。この場合は、ファイルを直してもう一度起動するだけで流れます。Line : 6 が、ファイルの中で失敗した行です。

③ Detected failed migration(失敗の記録が残った)

DDL をトランザクションで戻せない DB(MySQL など)や、トランザクションの外で流す文(PostgreSQL の CREATE INDEX CONCURRENTLY など)が途中で失敗すると、履歴表に success = false の行が残ります。 Flyway のソースでも、「DDL のトランザクションに対応していない、またはトランザクションの外で流した」ときに、失敗の行を書く作りになっていました。このときのログは「戻せた」ではなく、次の文になります。

SEVERE: Migration of schema "public" to version "3 - create orders" [non-transactional] failed! Please restore backups and roll back database and code!

この状態でもう一度起動すると、流す前の検証で止まります。

org.flywaydb.core.api.exception.FlywayValidateException: Validate failed: Migrations have failed validation
Detected failed migration to version 3 (create orders).
Please remove any half-completed changes then run repair to fix the schema history.

直す手順

  1. 失敗したファイルのうち、途中まで成功した部分を手で戻す(作りかけの表・インデックスを DROP する)
  2. SQL ファイルを直す
  3. repair を実行する(失敗の行が消える)
  4. もう一度 migrate(アプリを起動)

repair の結果は repairActions=[Removed failed migrations]、履歴表の V3 は Failed から Pending に戻り、次の migrate で Success になりました。Flyway のドキュメントにも、repair は「失敗した記録を消す。残ったオブジェクトは手で片付ける」とあります。

④ 小さい版を後から足した

V3 まで流した DB に、別のブランチで作った V2_5__add_phone_to_users.sql が後から入ってきた場合です。

org.flywaydb.core.api.exception.FlywayValidateException: Validate failed: Migrations have failed validation
Detected resolved migration not applied to database: 2.5.
To ignore this migration, set -ignoreMigrationPatterns='*:ignored'. To allow executing this migration, set -outOfOrder=true.
直し方 やること 向いている場面
版を振り直す(第一候補) V2_5__… を V4__… に名前を変える まだどの環境にも流していない
outOfOrder=true spring.flyway.out-of-order=true で、小さい版も流す 環境ごとに流れた順が違ってもよいと判断した
無視する ignore-migration-patterns: "*:ignored" 一時的に止めずに起動したい

outOfOrder=true で流したときは、警告が出ました。

WARNING: outOfOrder mode is active. Migration of schema "public" may not be reproducible.
INFO: Migrating schema "public" to version "2.5 - add phone to users" [out of order]

info の状態は Out of Order になります。開発者が同時に版を作ると起きやすいので、版に日時を使う(V2026.10.12.1__…)チームもあります。 ブランチの運用は、関連記事「Gitのブランチ戦略|Git Flow・GitHub Flowの違いと選び方」で扱っています。

⑤ Detected applied migration not resolved locally(ファイルを消した)

適用済みの V2_5__… をフォルダから消して起動しました。

Detected applied migration not resolved locally: 2.5.
If you removed this migration intentionally, run repair to mark the migration as deleted.

ブランチの切り替えでファイルが無くなっただけなら、ファイルを戻します。意図して消したなら repair で「削除済み」の印を付けます。

⑥ No Flyway database plugin found(DB 用モジュールが無い)

PostgreSQL 用のモジュールを外して動かすと、接続の時点で止まりました。

org.flywaydb.core.api.FlywayException: No Flyway database plugin found to handle jdbc:postgresql://127.0.0.1:55439/demo. See https://help.red-gate.com/help/flyway-cli12/help_4.aspx?topic=reference/usage/database-troubleshooting for troubleshooting

flyway-database-postgresql(MySQL なら flyway-mysql)を依存に足します。

⑦ No migrations found(場所が違う)

classpath:db/migration に1つもファイルが無いと、エラーにならずに警告だけ出て起動が続きます。

WARNING: No migrations found. Are your locations set up correctly?

spring.flyway.fail-on-missing-locations=true にすると、Unable to resolve location classpath:db/migration. で止まりました。フォルダ名を db/migrations(s 付き)や db.migration にしていないかを確かめます。

PostgreSQL の CREATE INDEX CONCURRENTLY が止まる

PostgreSQL で CREATE INDEX CONCURRENTLY(表をロックせずにインデックスを作る文)を流すと、既定の設定では終わりませんでした。 30秒待っても進まず、pg_stat_activity を見ると次の状態でした。

 state               | wait_event_type | wait_event | query
---------------------+-----------------+------------+---------------------------------------------------
 idle in transaction | Client          | ClientRead | SELECT COUNT(*) FROM pg_namespace WHERE nspname=$1
 active              | Lock            | virtualxid | CREATE INDEX CONCURRENTLY idx_users_name ON users ...

Flyway は既定で、ロックを「トランザクション単位」で取ります。そのトランザクションが開いたままなので、「他のトランザクションが終わるのを待つ」CONCURRENTLY が待ち続けた形です。Flyway のドキュメントにも「CREATE INDEX CONCURRENTLY のような文では false にする」とあります。

spring:
  flyway:
    postgresql:
      transactional-lock: false

false(Flyway の設定名は flyway.postgresql.transactional.lock)にすると、[non-transactional] として流れ、すぐに終わりました。インデックスの種類は、関連記事「PostgreSQLインデックスの種類|B-tree/GIN/GiST/BRIN実測」で扱っています。

既存の DB に Flyway を入れる(baseline)

すでにテーブルがある DB に、そのまま Flyway を入れると、次のエラーで止まります。

org.flywaydb.core.api.FlywayException: Found non-empty schema(s) "public" but no schema history table. Use baseline() or set baselineOnMigrate to true to initialize the schema history table.

手順

  1. 今の本番の DB から、テーブル定義を pg_dump --schema-only などで取り出す
  2. それを V1__baseline.sql として置く(新しい環境を作るときに使う)
  3. 次の変更から V2__… で書く
  4. 既存の DB では、初回だけ baseline-on-migrate: true で起動する
spring:
  flyway:
    baseline-on-migrate: true
    baseline-version: 1      # 既定も 1。ここまでは「流したことにする」

実行すると、V1 は流されず、V2 だけが流れました。

INFO: Creating Schema History table "public"."flyway_schema_history" with baseline ...
INFO: Successfully baselined schema with version: 1
INFO: Current version of schema "public": 1
INFO: Migrating schema "public" to version "2 - add email to users"
INFO: Successfully applied 1 migration to schema "public", now at version v2 (execution time 00:00.003s)
Versioned  1  baseline users          SQL       Ignored (Baseline)
Versioned  1  << Flyway Baseline >>   BASELINE  Baseline
Versioned  2  add email to users      SQL       Success

baseline-on-migrate は、空でない DB に履歴表が無いときだけ働きます。 履歴表を作った後は何もしませんが、接続先を間違えたときに気づきにくくなるので、導入が終わったら false に戻す運用もあります。スキーマの取り出し方は、関連記事「pg_dump/pg_restoreの使い方|バックアップとリストアの実行例」で扱っています。

Spring Boot で repair を自動で呼ぶ(FlywayMigrationStrategy)

Boot は起動時に Flyway.migrate() を呼びます。この動きを変えたいときは、FlywayMigrationStrategy の Bean を作ります。次は「開発環境だけ、先に repair する」例です。

package com.example.demo.config;

import org.springframework.boot.flyway.autoconfigure.FlywayMigrationStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("dev")
public class DevFlywayConfig {

    @Bean
    FlywayMigrationStrategy repairThenMigrate() {
        return flyway -> {
            flyway.repair();    // チェックサムのずれ・失敗の記録を直す
            flyway.migrate();
        };
    }
}

Boot 4 では、パッケージが org.springframework.boot.flyway.autoconfigure に変わっています(Boot 3 は org.springframework.boot.autoconfigure.flyway)。本番で毎回 repair すると、書き換えに気づけなくなるので、プロファイルで開発用に限っています。

Flyway の Java API を直接使う場合は、次の形です(この記事のエラー文は、この形で出したものです)。

Flyway flyway = Flyway.configure()
        .dataSource("jdbc:postgresql://localhost:5432/app", "app", password)
        .locations("classpath:db/migration")
        .validateMigrationNaming(true)
        .load();

MigrateResult result = flyway.migrate();
System.out.println(result.migrationsExecuted + " 件を適用、現在の版 " + result.targetSchemaVersion);

コマンドの一覧

コマンド 何をするか Boot の起動時
migrate 未適用のものを流す 自動で呼ばれる
info 各ファイルの状態(Pending・Success・Failed など)を表示 —
validate 適用済みのファイルとの差を確かめる validate-on-migrate=true で migrate の前に呼ばれる
repair 失敗の記録を消し、チェックサムを合わせ、消えたファイルに印を付ける —
baseline 既存 DB に履歴表を作り、指定の版までを「流したこと」にする baseline-on-migrate=true で自動
clean スキーマの中を全部消す 既定で禁止(clean-disabled=true)

clean を禁止のまま呼ぶと、次のエラーになりました。

org.flywaydb.core.api.FlywayException: Unable to execute clean as it has been disabled with the 'flyway.cleanDisabled' property.

Maven・Gradle のプラグイン(mvn flyway:repair、gradle flywayRepair)や、コマンドライン版(flyway repair)でも、同じ名前のコマンドが使えます。Actuator を入れると、/actuator/flyway で適用済みの一覧を見られます。公開の設定は、関連記事「Spring Boot Actuator設定|エンドポイント一覧と公開設定の雛形」で扱っています。

本番運用のルール表

ルール 理由 設定・やり方
適用済みのファイルは書き換えない チェックサムがずれて起動が止まる。環境ごとに形がずれる 変更は新しい版で書く
clean は禁止のまま 本番のデータが全部消える clean-disabled: true(既定)
ファイル名の規則を検証する _ 1つや小文字の v は黙って無視される validate-migration-naming: true
1ファイルには1つの目的 失敗したときに戻す範囲が分かりやすい テーブル作成とデータ投入を分ける
本番の前にバックアップ トランザクションで戻せない変更がある 流す前に取得する手順を決める
repair は手で、理由を残して実行 書き換えや失敗を隠してしまう 自動の repair は開発プロファイルだけ
outOfOrder は原則 false 環境ごとに流れた順が変わる 版の振り方をチームで決める
大きな表の変更は時間を見積もる 起動時に流れるので、終わるまでアプリが起動しない 検証環境で件数をそろえて計る
本番の DB ユーザーと分ける アプリの接続ユーザーに DDL 権限を持たせない spring.flyway.user・password で別ユーザー
CI で空の DB に全部流す 新しい環境で流れないファイルに早く気づく テスト用の PostgreSQL で migrate

CI で DB を立てて流す方法は、関連記事「CI/CDとは|GitHub Actionsで最初のパイプラインを作るまで」で、テストで本物の PostgreSQL を使う方法は、関連記事「Testcontainersの使い方|Spring BootでPostgreSQL」で扱っています。

よくある質問

Q. 取り消し(ロールバック)はどう書きますか。 A. U で始まる取り消しファイルは Flyway Teams(有料版)の機能で、オープンソース版の Flyway 12.4.0 では流れませんでした。オープンソース版では、取り消す内容を「新しい版」として書く(V5__drop_column_x.sql)形になります。

Q. テストのときだけ流したいデータがあります。 A. Boot のドキュメントでは、テスト用のファイルを src/test/resources 側に置く方法と、プロファイルごとに spring.flyway.locations を変える方法(例:classpath:/db/migration,classpath:/dev/db/migration)が紹介されています。

Q. Java でマイグレーションを書けますか。 A. 書けます。Boot のドキュメントでは、JavaMigration を実装した Bean が自動で Flyway に登録されるとあります。Flyway のチュートリアルでは、db/migration パッケージに V3__Anonymize のような名前のクラスを置き、BaseJavaMigration を継承しています。

Q. 起動時ではなく、デプロイの手順の中で流したいです。 A. spring.flyway.enabled=false でアプリの自動実行を止め、デプロイの手順で Maven・Gradle のプラグインやコマンドライン版の migrate を呼ぶ形があります。Flyway は流す前にロックを取る作りで(PostgreSQL ではアドバイザリロック)、ロックが取れないときの再試行回数は lock-retry-count(既定 50 回)で決まります。

Q. Liquibase とどちらがよいですか。 A. Flyway は SQL をそのまま書く形、Liquibase は XML・YAML などで変更を書く形が中心です。Boot はどちらにも対応していて、Boot 4 ではどちらも専用の starter(spring-boot-starter-flyway・spring-boot-starter-liquibase)を入れます。

まとめ

  • ファイル名は V版__説明.sql。区切りは __(2つ)。_ 1つや小文字の v は黙って無視される
  • Boot 4 は spring-boot-starter-flyway + flyway-database-postgresql などの DB 用モジュール
  • checksum mismatch は書き換えが原因。元に戻すか、意図した変更なら repair。形の変更は新しい版で
  • PostgreSQL の SQL エラーは全部戻るので、直して再起動。失敗の記録が残ったら、手で戻して repair
  • 小さい版を後から足すと out of order。版を振り直すのが第一候補
  • 既存 DB は baseline-on-migrate。CREATE INDEX CONCURRENTLY は postgresql.transactional-lock: false

参考・出典

確認日はいずれも 2026年10月13日です。

  • Spring Boot ドキュメント「Database Initialization」(Execute Flyway Database Migrations on Startup):https://docs.spring.io/spring-boot/how-to/data-initialization.html
  • Spring Boot 4.0 Migration Guide:https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-4.0-Migration-Guide
  • Spring Boot ソース(タグ v4.1.1、FlywayProperties ほか):https://github.com/spring-projects/spring-boot/tree/v4.1.1/module/spring-boot-flyway
  • Flyway(GitHub、ソースとドキュメント・タグ flyway-12.4.0):https://github.com/flyway/flyway
  • Redgate Flyway ドキュメント「Migrations」:https://documentation.red-gate.com/fd/migrations-271585107.html
  • Redgate Flyway ドキュメント「SQL Migration Separator」:https://documentation.red-gate.com/fd/flyway-sql-migration-separator-setting-277579038.html
  • Flyway ドキュメント「Repair」(GitHub、タグ flyway-12.4.0):https://github.com/flyway/flyway/blob/flyway-12.4.0/documentation/Reference/Commands/Repair.md

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Flywayの使い方|Spring Boot・命名規則・失敗時の直し方」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?