Testland
Browse all skills & agents

flyway-migrations

Authors and runs Flyway database migrations - versioned (`V1__add_users.sql`), repeatable (`R__refresh_views.sql`), and undo (`U1__remove_users.sql`) migration files in `db/migration/`; runs `flyway migrate` / `info` / `validate` / `clean` / `baseline` / `repair`; tracks state in the `flyway_schema_history` table; supports 50+ databases including Oracle / SQL Server / MySQL / PostgreSQL / MariaDB / Snowflake / BigQuery; integrates with Maven, Gradle, CLI, and Docker. Use when the user works with Flyway-managed schemas, asks about migration ordering, or needs CI gates on schema changes.

Install with skills.sh (any agent)

npx skills add testland/qa --skill flyway-migrations
View source

flyway-migrations

Overview

Flyway tracks applied migrations in a per-database flyway_schema_history table and applies pending migrations in order by version number (fw-how (opens in new window)).

When to use

  • The repo has a db/migration/ (or configured) directory of V*.sql / R*.sql files.
  • The user works with Flyway CLI / Docker / Maven plugin / Gradle plugin.
  • A CI workflow needs a migration gate against a per-PR ephemeral database (e.g., Testcontainers) before merge.
  • The team migrates from manual SQL scripts to versioned migration control.

How to use

Follow Steps 1 - 7 below in order; each numbered step is the single source for that part of the workflow.

Step 1 - Install

Flyway runs on Windows, macOS, Linux, and Docker, plus Maven and Gradle plugin distributions (fw-home (opens in new window)). Common install paths:

# Docker (zero-install for CI)
docker run --rm flyway/flyway -url=jdbc:postgresql://host/db -user=usr -password=pwd migrate

# Homebrew (macOS / Linux)
brew install flyway

# Maven plugin (Spring Boot etc.)
# add to pom.xml under <build><plugins>

Step 2 - First migration

Migrations may be written in SQL, Java, or other scripting languages (fw-how (opens in new window)). File naming places migrations in the configured locations (default db/migration):

db/migration/
├── V1__create_users.sql
├── V2__add_email_index.sql
├── R__refresh_active_users_view.sql      # repeatable, reruns on checksum change
└── U1__remove_users.sql                   # undo (Flyway Teams)

The prefix scheme:

PrefixTypeReruns?Use
V<n>__VersionedOnceNew schema changes; immutable after merge
R__RepeatableWhen checksum changesViews / stored procs / seed data
U<n>__UndoInverse of versionedRollback (Teams edition)

__ (double underscore) separates version + description; .sql (or configured suffix) marks the file as a migration.

Step 3 - Core commands

The daily loop is flyway info (preview pending) -> flyway migrate (apply pending) -> flyway validate (checksum-verify applied files before deploy). After a failed migration, flyway repair fixes flyway_schema_history - never edit an applied file. Full command reference (baseline, undo, clean, and the rest): references/commands.md.

Step 4 - Pending-migration semantics

Migrations with a version lower than the history table's current version are ignored by default; the rest are pending - available but not applied (fw-how (opens in new window)). Safety property: a developer who pulls main and runs flyway migrate applies only the new migrations; those already in flyway_schema_history are not re-run.

Step 5 - Configuration

Configuration via flyway.conf file, env vars (FLYWAY_*), or CLI flags. Key settings:

flyway.url=jdbc:postgresql://localhost:5432/mydb
flyway.user=myuser
flyway.password=mypass
flyway.locations=filesystem:db/migration,classpath:db/migration
flyway.baselineOnMigrate=true        # auto-baseline empty schemas
flyway.cleanDisabled=true            # CRITICAL for prod - disable destructive `clean`
flyway.outOfOrder=false              # reject migrations with versions lower than max applied
flyway.validateOnMigrate=true        # checksum-validate before applying

cleanDisabled=true is a mandatory production guard - flyway clean drops every object in the schema. Always set this in production config; only enable for ephemeral test databases.

Step 6 - CI integration

Gate every PR on an ephemeral DB (Docker / Testcontainers): spin the DB, apply migrations, run tests against the migrated schema. The full GitHub Actions job and the Testcontainers @BeforeAll pattern are in references/commands.md.

Step 7 - Composition with sister tools

Before merge, apply adversarial review of new migrations - classify each as additive / breaking / data-loss / locking.

Worked example

Add an index on users.email and ship it through CI:

  1. Create db/migration/V2__add_email_index.sql with CREATE INDEX idx_users_email ON users(email);.
  2. Locally run flyway info - it lists V2 as pending while V1 shows applied.
  3. flyway migrate applies only V2 and appends a row to flyway_schema_history with its checksum.
  4. In the PR, CI starts an ephemeral Postgres, runs the Docker flyway ... migrate, then mvn test against the migrated schema.
  5. A teammate later edits the merged V2 file; on their next run flyway validate fails with a checksum mismatch, so they add V3__... instead of mutating V2.

Anti-patterns

Anti-patternWhy it failsFix
Edit a previously-applied versioned migrationChecksum mismatch; validate fails on next runAdd a new V_n+1 migration that adjusts
cleanDisabled=false in production configOne stray flyway clean drops the schemaAlways cleanDisabled=true (Step 5)
Mixing versioned + repeatable migrations for the same objectRepeatable applies after every versioned change → racePick one per object class
outOfOrder=true without team agreementLower-version migrations apply mid-stream; ordering breaksDefault false; enable per change with team review
Skip CI gating on per-PR ephemeral DBMigrations break in production for the first timeAlways run migrations in CI (Step 6)

Limitations

  • Undo migrations are a Teams (paid) feature - OSS users implement rollback manually via inverse versioned migrations.
  • flyway clean is irreversible; the cleanDisabled=true guard is the only protection.
  • 50+ supported DBMS but rule depth varies - consult per-database pages on fw-home (opens in new window) for vendor-specific syntax.
  • Requires JVM (CLI bundles its own JRE; Docker / Maven plugin inherit it).

References

  • references/commands.md - full command table + CI job
  • fw-home (opens in new window) - main documentation, command list, supported databases
  • fw-how (opens in new window) - conceptual model: schema_history table, pending-migration semantics, ordering
  • github.com/flyway/flyway - repository
  • liquibase-migrations, atlas-migrations, sqlmesh-migrations - sister tools (Liquibase = changelog-driven; Atlas = declarative HCL; SQLMesh = data-pipeline + schema)

Flyway command reference and CI integration

View source (opens in new window)

Flyway command reference and CI integration

Command reference

Per fw-home (opens in new window), Flyway's commands are Migrate, Clean, Info, Validate, Undo, Baseline, Repair, Check, and Snapshot.

CommandUse
flyway migrateApply pending migrations
flyway infoShow applied + pending migration list
flyway validateVerify checksums of applied migrations vs disk files
flyway baselineMark a legacy schema state as baseline (skip prior migrations)
flyway repairFix a broken flyway_schema_history (e.g., after a failed migration)
flyway undoRoll back the last versioned migration (Teams)
flyway cleanDrop all objects in the schema (production-disabled by default)

CI integration

Pattern: ephemeral DB (Docker / Testcontainers) per PR, apply migrations, run tests against the migrated schema.

- name: Spin up Postgres
  uses: docker/setup-buildx-action@v3
- run: docker run -d --name pg -p 5432:5432 -e POSTGRES_PASSWORD=pwd postgres:16
- name: Apply migrations
  run: |
    docker run --rm --network=host \
      -v "$PWD/db/migration:/flyway/sql" \
      flyway/flyway -url=jdbc:postgresql://localhost:5432/postgres \
      -user=postgres -password=pwd migrate
- name: Run tests
  run: mvn test

For full integration with testcontainers (in the qa-test-environment plugin): spin up the DB via Testcontainers, then call Flyway.configure() in JUnit @BeforeAll.

Related skills

atlas-migrations

Authors and runs Atlas database schema migrations - declarative HCL or SQL schema definition with `atlas schema apply` for desired-state apply OR `atlas migrate diff` to generate versioned migrations against a dev DB; `atlas migrate apply` to deploy; `atlas migrate lint` to flag destructive / locking / data-loss patterns; `atlas migrate hash` to detect tampering. Supports PostgreSQL, MySQL, SQL Server, ClickHouse, SQLite, MariaDB, Snowflake, Oracle, Redshift, Spanner, CockroachDB, Databricks. Use when the user wants Terraform-style declarative DB schema management or modern SQL-first migration linting beyond Flyway / Liquibase.

liquibase-migrations

Authors and runs Liquibase database migrations - changelog-driven schema management with changesets in XML / YAML / JSON / SQL formats; supports `liquibase update` / `status` / `rollback` / `tag` / `history` lifecycle; offers per-changeset preconditions, contexts and labels for selective execution, and rollback semantics; tracks state in `DATABASECHANGELOG` + `DATABASECHANGELOGLOCK` tables. Use when the user works with Liquibase-managed schemas (Spring Boot heritage, polyglot DB shops), needs cross-DBMS portable migrations, or requires fine-grained rollback control.

migration-operation-taxonomy

Classifies every DDL and DML statement in a database migration into an eight-category operation taxonomy (additive, backwards-compatible alter, locking, lock-escalating, breaking, data-loss, unsafe default, index-missing foreign key) and assigns a Critical, Warning, or Info severity justified by the lock mode and table-rewrite behavior the target engine actually performs. Records where PostgreSQL and MySQL/InnoDB diverge for the same logical statement, and where behavior is version-gated (PostgreSQL 11 removed the table rewrite for a constant DEFAULT; MySQL 8.0.12 made ADD COLUMN instant). Use when a migration file appears in a diff or a review queue and someone must decide, before it reaches a production-sized table, which statements are safe and which will stall writes or destroy data.

sqlmesh-migrations

Authors and runs SQLMesh - data-transformation framework with version control, virtual data environments, automatic breaking-vs-non-breaking change classification, and downstream impact analysis; supports `sqlmesh init` / `plan` / `apply` / `run` / `audit` / `test` lifecycle; covers DuckDB, Postgres, Snowflake, BigQuery, Redshift, Databricks. Use when the user works with SQL data pipelines (warehouse + dbt-adjacent ELT), needs safer model evolution than dbt's deploy-and-pray, or wants the strongest impact-analysis story in the OSS data tooling space.