MigAce migrates a database with real data and then proves the result is identical to the schema your application expects, down to the last constraint. No drift, no surprises in production.
# migrations/2026-11-11-add-customer-email.yaml id: add-customer-email parts: - sql: ALTER TABLE customer ADD COLUMN email text - data: UPDATE customer SET email = legacy_mail - sql: ALTER TABLE customer ALTER email SET NOT NULL $ ./gradlew migaceVerify ✔ schema A generated from Hibernate model ✔ schema B restored from dump + 214 snippets applied ✔ A ≡ B 0 differences (digest 9f3c…e1a7) ✔ HA check compatible with release 4.12
Every build runs the same loop. If a migration doesn't produce exactly the expected schema on a database that already contains data, the build fails, long before production.
Born in a long-running Java EE project and rebuilt from scratch for PostgreSQL.
Production schema matches the Hibernate-generated DDL exactly, verified on every build.
YAML snippets made of small parts. Each part is logged and skipped once applied, so a failed run simply resumes.
Adding NOT NULL or unique constraints is tested against data, not just an empty schema.
First-class data and repair snippets, separate from schema changes and fully traceable.
Classifies every change as compatible or breaking, so older app versions keep running during a Kubernetes rollout.
The app checks a hash of the live schema and refuses to start against an unexpected database.
Generate realistic data for every new table and column so each snippet is exercised.
A Kotlin Gradle plugin with Testcontainers built in. One task: migaceVerify.
Execute from an init container or job, or export a plain SQL script for your DBAs.
Indicative comparison for planned features. MigAce is not released yet.
| Capability | MigAce | Typical versioned tools |
|---|---|---|
| Proves migrated schema = ORM model | Yes | Manual / partial |
| Tests migrations against existing data | Built in | Up to you |
| Resumable, part-level execution log | Yes | Per-file |
| Rolling-update compatibility check | Yes | Rare |
| Schema digest check at app startup | Yes | Rare |
The plugin is not published yet. This is what using it will look like.
// build.gradle.kts plugins { id("org.migace") version "0.1.0" } migace { database = postgres("17") snapshot = file("db/baseline.dump") snippets = file("db/migrations") }