flyway-migrations · git:20260718.ab29907 · 2026-07-18 · sha256 bc3de29fe38a3192

flyway-migrations git:20260718.ab29907A

Immutable. This exact content never changes and is served at /api/v1/blob/bc3de29fe38a3192.

---
name: flyway-migrations
description: "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."
---

# flyway-migrations

## Overview

Per [documentation.red-gate.com/fd/flyway-documentation-138346877.html][fw-home]:

[fw-home]: https://documentation.red-gate.com/fd/flyway-documentation-138346877.html

> "Redgate Flyway extends DevOps to your databases to accelerate
> software delivery and ensure quality code so you can deploy with
> confidence. From version control to continuous delivery, Flyway
> builds on application delivery processes to automate database
> deployments."

Flyway tracks applied migrations in a per-database
`flyway_schema_history` table (per [documentation.red-gate.com/fd/quickstart-how-flyway-works-184127223.html][fw-how]):

[fw-how]: https://documentation.red-gate.com/fd/quickstart-how-flyway-works-184127223.html

> "[The flyway_schema_history table] is used to track the changes
> to the database."

> "The migrations are applied in order based on their **version
> number**."

## 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.

## Step 1 - Install

Per [fw-home][fw-home]: "Flyway Command Line runs on Windows,
macOS, Linux, and is available on docker." Plus Maven plugin and
Gradle Plugin distributions.

Common install paths (consult [fw-home][fw-home] for current download
URL by platform):

```bash
# 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

Per [fw-how][fw-how], migrations may be "written in either SQL,
Java, or other scripting languages." File-naming convention 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:

| Prefix | Type | Reruns? | Use |
|---|---|---|---|
| `V<n>__` | Versioned | Once | New schema changes; immutable after merge |
| `R__` | Repeatable | When checksum changes | Views / stored procs / seed data |
| `U<n>__` | Undo | Inverse of versioned | Rollback (Teams edition) |

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

## Step 3 - Core commands

Per [fw-home][fw-home]: "Flyway has the following commands at its
disposal: Migrate, Clean, Info, Validate, Undo, Baseline, Repair,
Check and Snapshot."

| Command | Use |
|---|---|
| `flyway migrate` | Apply pending migrations |
| `flyway info` | Show applied + pending migration list |
| `flyway validate` | Verify checksums of applied migrations vs disk files |
| `flyway baseline` | Mark a legacy schema state as baseline (skip prior migrations) |
| `flyway repair` | Fix a broken `flyway_schema_history` (e.g., after a failed migration) |
| `flyway undo` | Roll back the last versioned migration (Teams) |
| `flyway clean` | **Drop all objects** in the schema (production-disabled by default) |

## Step 4 - Pending-migration semantics

Per [fw-how][fw-how]:

> "If their version number is lower than the table's current
> version, they are ignored by default. The remaining migrations
> are the **pending migrations**: available, but not applied."

This is the safety property: a developer who pulls main with new
migrations and runs `flyway migrate` applies only the new ones; old
ones 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:

```properties
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

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

```yaml
- 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`.

## Step 7 - Composition with sister tools

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

## Anti-patterns

| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Edit a previously-applied versioned migration | Checksum mismatch; `validate` fails on next run | Add a new V_n+1 migration that adjusts |
| `cleanDisabled=false` in production config | One stray `flyway clean` drops the schema | Always `cleanDisabled=true` (Step 5) |
| Mixing versioned + repeatable migrations for the same object | Repeatable applies after every versioned change → race | Pick one per object class |
| `outOfOrder=true` without team agreement | Lower-version migrations apply mid-stream; ordering breaks | Default `false`; enable per change with team review |
| Skip CI gating on per-PR ephemeral DB | Migrations break in production for the first time | Always 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][fw-home] for vendor-specific syntax.
- Requires JVM (CLI bundles its own JRE; Docker / Maven plugin
  inherit it).

## References

- [fw-home][fw-home] - main documentation, command list, supported
  databases
- [fw-how][fw-how] - conceptual model: schema_history table,
  pending-migration semantics, ordering
- github.com/flyway/flyway - repository
- [`liquibase-migrations`](../liquibase-migrations/SKILL.md),
  [`atlas-migrations`](../atlas-migrations/SKILL.md),
  [`sqlmesh-migrations`](../sqlmesh-migrations/SKILL.md) - sister
  tools (Liquibase = changelog-driven; Atlas = declarative HCL;
  SQLMesh = data-pipeline + schema)