> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/database-devops/use-db-devops/changelogs-and-schema-changes/flyway/flyway-migrations-file-structure.md).

# Working with Flyway Migration Files

Flyway provides a versioned, convention-driven approach to managing database schema changes. When paired with Harness Database DevOps, Flyway migrations become fully automated, GitOps-driven, and Kubernetes-native. This guide walks you through how to structure your migration files, configure the flyway.toml manifest, and prepare your repository for seamless deployments.

### Flyway migration file structure <a href="#flyway-migration-file-structure" id="flyway-migration-file-structure"></a>

A typical Flyway-compatible repository looks like this:

```tree
.
├── migrations/
│   ├── V1__init.sql
│   ├── V2__create_users.sql
│   ├── V3__add_orders_table.sql
│   └── U1__revert_init.sql
│   └── U2__drop_users.sql
├── flyway.toml
└── README.md
```

Recommended naming conventions:

1. `migrations/` as the folder root.
2. `flyway.toml` placed at the top level.
3. Semantic versioning (V1, V2, V3…) to maintain predictable ordering.

### Create versioned migration files <a href="#create-versioned-migration-files" id="create-versioned-migration-files"></a>

Flyway processes migrations based on its naming convention:

#### 1. Versioned migrations <a href="#id-1-versioned-migrations" id="id-1-versioned-migrations"></a>

Executed once and never modified.

```sql
V<version>__<description>.sql
```

Examples:

1. `V1__init.sql`
2. `V2__add_users_table.sql`
3. `V3__add_indexes.sql`

Each file contains SQL statements meant to evolve your schema:

```sql
-- V2__create_users.sql
CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  username VARCHAR(200) NOT NULL UNIQUE,
  created_at TIMESTAMP DEFAULT NOW()
);
```

#### 2. Undo migrations <a href="#id-2-undo-migrations" id="id-2-undo-migrations"></a>

Flyway supports a special class of migrations known as Undo Migrations, which use the `U<version>__<description>.sql` naming pattern.

```sql
U001__revert_init.sql
U002__remove_users_table.sql
```

Undo migrations allow you to reverse the effects of a corresponding versioned migration. For example:

| **Forward Migration**  | **Undo Migration**    | **Purpose**                             |
| ---------------------- | --------------------- | --------------------------------------- |
| `V1__init.sql`         | `U1__revert_init.sql` | Rolls back schema objects created in V1 |
| `V2__create_users.sql` | `U2__drop_users.sql`  | Removes objects introduced in V2        |

Undo migrations are executed when you run the 'DB Schema Rollback' step in your pipeline. This allows for more controlled rollback than relying solely on backups or manual scripts.

#### 3. Create the flyway.toml configuration file (optional) <a href="#id-3-create-the-flywaytoml-configuration-file-optional" id="id-3-create-the-flywaytoml-configuration-file-optional"></a>

The `flyway.toml` file defines how Flyway connects to your database and manages migrations.

A basic configuration looks like this:

```toml
[flyway]
# Relative path to your migration files <a href="#relative-path-to-your-migration-files" id="relative-path-to-your-migration-files"></a>
locations = ["filesystem:migrations"]

# Default schema used for tracking metadata <a href="#default-schema-used-for-tracking-metadata" id="default-schema-used-for-tracking-metadata"></a>
defaultSchema = "public"

# (Optional) Naming validation <a href="#optional-naming-validation" id="optional-naming-validation"></a>
validateMigrationNaming = true

# (Optional) Disable clean operations in production <a href="#optional-disable-clean-operations-in-production" id="optional-disable-clean-operations-in-production"></a>
cleanDisabled = true
```

You can also define dynamic configurations using profiles. For example:

```toml
[environments.dev]
url = "jdbc:postgresql://dev-db:5432/app"
user = "app_user"
password = "password123"

[environments.qa]
url = "jdbc:postgresql://qa-db:5432/app"
user = "qa_user"
password = "securepass"
```

{% hint style="info" %}
**NOTE**

These environments are not used directly by Harness (Harness uses its own JDBC connectors). The `flyway.toml` is primarily for local testing or CI pipelines that run Flyway commands outside of Harness.
{% endhint %}

### Best practices to create migrations files <a href="#best-practices-to-create-migrations-files" id="best-practices-to-create-migrations-files"></a>

Some best practices to follow when creating Flyway migrations:

1. Maintain Immutable Versioned Migrations Never modify an existing V1\_\_\*.sql file. If you need to correct a change: Create a new version file, e.g., `V4__fix_users_column.sql`.
2. Keep Migrations Small and Incremental. Smaller files ensure better readability and reduce risk during execution.
3. Enable naming validation in flyway.toml to enforce team-wide consistency: `validateMigrationNaming = true`
4. Use a Single Source of Truth. All schema changes must originate in Git, not from manual DB edits. Harness will ensure schema consistency across environments.

### Next steps <a href="#next-steps" id="next-steps"></a>

* Go to [Build a Changelog](/database-devops/use-db-devops/changelogs-and-schema-changes/liquibase/build-a-changelog.md) to learn how to generate changelogs for SQL databases.
