Schemint

paste PostgreSQL or JSON, get your schema reviewed like a senior would

Flyway migrations: versioned naming and FK-safe ordering

Flyway's contract is simple: versioned files, applied exactly once, in version order, checksummed forever. Most Flyway pain is someone fighting one of those three properties.

The naming rules

V1__create_customers.sql
V2__create_orders.sql
V2.1__orders_status_index.sql
R__refresh_reporting_views.sql

Pick one version scheme per repo and write it down. Sequential integers are fine for a small team; timestamp versions avoid collisions when several branches mint migrations in parallel (two people both creating V17 on the same day is a merge conflict Flyway can't see, it just applies whichever lands first and fails, or worse, doesn't fail, on the other).

Order is part of the schema: FKs

Within one file, statement order matters the same way it does in psql: a foreign key can only reference a table that already exists.

-- V1__create_customers_and_orders.sql
CREATE TABLE customers (
    id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    email VARCHAR(180) UNIQUE NOT NULL
);

CREATE TABLE orders (
    id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    customer_id BIGINT NOT NULL REFERENCES customers (id),
    total NUMERIC(12, 2) NOT NULL
);

Parents first, children after; for a bigger graph that means a topological sort by FK dependencies (Schemint orders the generated migration that way automatically). The alternative, creating tables in any order and bolting FKs on with ALTER TABLE at the end, also works and is sometimes necessary for circular references; it's just noisier to read and review.

Across files the same logic holds: the migration that adds orders must carry a version after the one that added customers. Flyway won't reorder for you; the version sequence is the dependency declaration.

History is append-only

Flyway records a checksum per applied migration and validates it on every run. Editing a migration that already ran anywhere, including a teammate's laptop, produces FlywayValidateException: Migration checksum mismatch. The rule that follows:

Corollary: migrations shouldn't be clever. No environment conditionals, no data reads that depend on the day they run. A migration is a letter to every future environment, including the CI database created from scratch tomorrow, and it must say the same thing to all of them.

A checklist that survives code review

Paste your CREATE TABLEs into Schemint in any order; the generated V1__ migration comes out FK-topologically sorted, ready to be the first file in the history.

Related