Skip to content

Native migration runner

Pro Plus. Settings → Pro Plus → Migrations. Versioned SQL migrations applied in order, tracked in a single quay_schema_migrations table. Zero external CLI required — goodbye, flyway / liquibase / dbmate / goose.

Quay reads versioned migration files from a folder you point it at:

my-project/
└── migrations/
├── 0001_initial.up.sql
├── 0001_initial.down.sql
├── 0002_add_users.up.sql
└── 0002_add_users.down.sql
ConventionNotes
Filename<version>_<name>.up.sql (and optional matching .down.sql)
VersionInteger or semver-ish (0001, 20260509120000, 1.0.0); sorted lexicographically
NameFree-form; lowercase + underscores by convention
BodyRaw SQL — Quay sends each file’s body to the engine through run_query

A missing .down.sql means “no rollback for this version” — the runner will refuse to roll back past it (asks you to add the down or skip with a force flag).

In the migrations panel:

  1. Pick an active SQL session (PG / MySQL / SQLite / MSSQL / DuckDB / ClickHouse — graph + cloud-warehouse engines aren’t yet wired)
  2. Paste the absolute path to your migrations/ folder
  3. Click Discover — Quay reads + sorts the files, queries quay_schema_migrations for what’s already applied, shows a list with ✓ (applied) / · (pending) markers
  4. Click Apply N pending — Quay creates the tracking table if missing, runs each pending migration’s .up.sql in order, records the version + name + timestamp on success
  5. Each migration runs in its own transaction (where the engine supports it). A failure aborts that migration’s transaction + stops the run; previously-applied migrations stay applied.

Rollback last runs the most-recent applied version’s .down.sql, removes the tracking row. The dialog asks for confirmation — rollbacks on prod also require typed-name confirm (Confirmation rules).

Repeat to roll back further. There’s no “rollback to version X” yet — add it via N successive rollbacks.

Two paths:

  1. Hand-write — create the .up.sql + .down.sql files with your editor of choice
  2. Generate from schema diff — run Schema diff, click “Save as migration” in the diff result. Quay writes a paired <next-version>_<auto-name>.up.sql + .down.sql into your migrations folder

The generated migration is a starting point — review the SQL before committing. Quay errs toward “ALTER” rather than “DROP and recreate” where the change is reversible, but for irreversible changes (DROP COLUMN) the auto-rollback is -- TODO: write the inverse.

Quay creates this on first apply:

CREATE TABLE quay_schema_migrations (
version VARCHAR(255) PRIMARY KEY,
name VARCHAR(1024) NOT NULL,
applied_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
checksum VARCHAR(64)
);

The dialect-appropriate version of that DDL is in the Tracking-table DDL card on the migrations panel. Copy + run on every connection you want to track migrations on.

checksum is SHA-256 of the .up.sql body. It’s recorded but not yet enforced — a v0.4 feature is to detect when a checked-in migration’s body has been edited after it was applied (which would mean different environments have different schemas under the same version number).

  • Per-environment migration paths — same migrations/ folder applied to dev / staging / prod in turn. The quay_schema_migrations row is per-database, so each env tracks independently.
  • Squash on release — at release boundary, dump the current schema with Backup, make it a single 0001_baseline.up.sql, archive the old per-version files. New environments restore from the baseline; existing environments are unaffected.
  • Multiple folders — Quay tracks one folder per session at a time. For multi-folder projects (e.g. core + per-tenant), run the panel multiple times.
  • NoSQL migrations (Mongo / Redis schema versioning) — patterns exist (e.g. Mongoose migrations) but Quay’s runner is SQL-only for now. Mongo-shaped migration runner is a v0.5 candidate.
  • Repeatable migrations (Flyway-style R__) for views / procedures — not yet; for now, just include them as a normal versioned migration that DROPs + CREATEs.