Database Migration Tools: Flyway vs Liquibase vs Atlas vs Goose
Database schema changes are the most anxiety-inducing part of deployment. Application code can be rolled back instantly. A botched database migration can corrupt data, break referential integrity, or lock tables for minutes. Getting migrations right requires tooling that tracks what has been applied, what needs to be applied, and in what order.
Most web frameworks include basic migration support (Rails migrations, Django migrations, Alembic for SQLAlchemy). But standalone migration tools offer advantages for polyglot teams, microservice architectures, and organizations that want database schema management independent of their application framework.
What Migration Tools Do
At their core, migration tools:
- Track applied migrations: Maintain a record of which migrations have been applied to each database
- Apply pending migrations: Execute migrations in the correct order on target databases
- Ensure consistency: Prevent out-of-order or conflicting migrations
- Support rollback: Provide mechanisms for reverting migrations (with caveats)
- Validate state: Verify that the database schema matches the expected state
Flyway
Flyway is one of the most widely used database migration tools, particularly in the Java ecosystem. According to Red Gate (which acquired Flyway), the tool uses SQL-based migrations with a simple naming convention and linear versioning.
How It Works
Migrations are SQL files following a naming convention: V1__create_users_table.sql, V2__add_email_to_users.sql. Flyway executes them in order and records the result in a flyway_schema_history table.
The approach is intentionally simple — write SQL, name it correctly, run flyway migrate.
Strengths
- Simplicity: Migrations are plain SQL files. No new syntax to learn
- Convention over configuration: The naming convention handles ordering. No manifest files or migration registry
- Broad database support: PostgreSQL, MySQL, SQL Server, Oracle, SQLite, MariaDB, CockroachDB, and many more
- Java integration: First-class integration with Spring Boot, Maven, and Gradle
- Baseline: Can adopt Flyway on existing databases by baselining from the current schema
- Repeatable migrations: Support for migrations that can be re-run (views, stored procedures, seed data)
Limitations
- SQL-only migrations by default: Java or Kotlin callbacks are available but less common. No built-in support for scripting languages
- Linear versioning: Migrations must be applied in strict version order, which can cause conflicts in teams with parallel development
- Rollback is paid: Down migrations (undo) are only available in the paid Teams/Enterprise editions
- Limited diff capabilities: Cannot compare database schema against desired state
Best for: Java/JVM teams wanting straightforward SQL-based migrations.
Pricing: Community (free). Teams at $497/year per 10 schemas. Enterprise pricing available.
Liquibase
Liquibase provides database-agnostic migrations using XML, YAML, JSON, or SQL changesets. According to the company, Liquibase supports over 50 database platforms and provides database-independent migrations that can target multiple database types from the same changesets.
How It Works
Migrations are defined as "changesets" in a changelog file. Each changeset describes a schema change using either database-agnostic XML/YAML/JSON or native SQL. Liquibase translates abstract changesets into the appropriate SQL for the target database.
Strengths
- Database-agnostic changesets: Write a migration once and apply it to PostgreSQL, MySQL, Oracle, and others without rewriting SQL
- Multiple formats: Define migrations in XML, YAML, JSON, or SQL — use whichever your team prefers
- Rollback support: Free, built-in rollback for standard change types (create table, add column, etc.)
- Preconditions: Conditional migration execution — only apply a migration if certain conditions are met (table exists, column does not exist)
- Diff and snapshot: Compare database schemas, generate diffs, and create snapshots of database state
- Context and labels: Apply different migrations to different environments (development data in dev, not in production)
Limitations
- Complexity: The flexibility comes with more concepts to learn — changelogs, changesets, contexts, labels, preconditions, rollback blocks
- XML verbosity: XML-based migrations are verbose compared to plain SQL
- Slower adoption outside Java: While Liquibase works with any language, the ecosystem is Java-centric
- Changeset immutability: Changesets should never be modified after deployment, which can confuse developers used to amending migrations
Best for: Teams needing database-agnostic migrations or supporting multiple database platforms.
Pricing: Open source (free). Pro from $175/month. Enterprise pricing available.
Atlas
Atlas is a newer, modern database migration tool that takes a declarative approach. According to Ariga (the company behind Atlas), you define your desired schema state, and Atlas generates the migrations needed to reach that state — similar to how Terraform works for infrastructure.
How It Works
Atlas supports two workflows:
- Declarative: Define your desired schema in HCL or SQL, and Atlas generates and applies the necessary migration statements
- Versioned: Traditional version-based migrations with additional safety features
The declarative approach is the differentiator. Instead of writing migration steps manually, you describe the end state, and Atlas figures out the steps.
Strengths
- Declarative schema management: Define what you want, not how to get there. Atlas handles the diff
- Schema-as-code: Schema definitions are version-controlled, reviewable, and testable
- Migration linting: Atlas analyzes migrations for common issues — destructive changes, data-dependent changes, missing indexes
- Migration directory integrity: Cryptographic verification that migration files have not been tampered with
- Modern CLI: Clean, developer-friendly CLI with good error messages
- ORM integration: Generate Atlas schemas from your ORM models (GORM, Sequelize, Django, SQLAlchemy, Ent)
- CI/CD integration: GitHub Actions, GitLab CI, and other CI tools for automated migration review
Limitations
- Younger tool: Less battle-tested than Flyway or Liquibase at enterprise scale
- Smaller community: Fewer resources, tutorials, and community answers
- HCL schema format: While SQL schema is supported, some features work best with HCL, adding another format to learn
- Database support: Focused on PostgreSQL, MySQL, MariaDB, SQLite, and SQL Server. Fewer exotic database targets than Liquibase
Best for: Teams that prefer declarative schema management and want modern migration safety features.
Pricing: Open source (free). Atlas Cloud with additional features available.
Goose
Goose is a lightweight, no-frills migration tool originally built for Go projects but usable with any stack. Migrations are SQL files or Go functions.
How It Works
Migration files are named with a version prefix: 001_create_users.sql. Each file contains -- +goose Up and -- +goose Down sections. Goose applies the Up section and records the version. Rollback executes the Down section.
Strengths
- Minimal: A single binary with no dependencies. No configuration files needed
- SQL and Go migrations: SQL files for schema changes, Go files for data migrations that need logic
- Built-in rollback: Down migrations are a core feature, not a paid add-on
- Fast: No JVM startup time. The Go binary starts instantly
- Simple: Few concepts to learn. Migrations, up, down, status — that is essentially it
- Embeddable: Can be embedded in Go applications as a library for programmatic migration management
Limitations
- Go-centric ecosystem: While SQL migrations work with any language, Go migrations require Go
- No database-agnostic migrations: Migrations are raw SQL tied to a specific database dialect
- No declarative mode: Purely versioned migrations
- Limited team features: No built-in conflict detection, migration linting, or policy enforcement
- Basic CLI: Functional but minimal compared to Atlas or Liquibase
Best for: Go teams and anyone wanting the simplest possible migration tool.
Pricing: Free and open source.
Comparison Table
| Feature | Flyway | Liquibase | Atlas | Goose | |---------|--------|-----------|-------|-------| | Migration format | SQL | XML/YAML/JSON/SQL | HCL/SQL | SQL/Go | | Declarative mode | No | No | Yes | No | | Rollback (free) | No | Yes | Yes | Yes | | Database-agnostic | No | Yes | No | No | | Migration linting | No | Limited | Yes | No | | Schema diff | No | Yes | Yes | No | | ORM integration | Limited | Yes | Yes | Limited | | Complexity | Low | High | Medium | Very Low | | Best for | JVM teams | Multi-DB teams | Modern teams | Go teams |
Choosing a Migration Tool
Choose Flyway if:
- You are in the Java/JVM ecosystem
- You want the simplest SQL-based migration workflow
- Your team is comfortable without free rollback support
Choose Liquibase if:
- You support multiple database platforms
- You need database-agnostic migrations
- You want built-in diff and snapshot capabilities
Choose Atlas if:
- You prefer declarative schema management (Terraform-style)
- Migration safety (linting, integrity checks) is important
- You want modern tooling with ORM integration
Choose Goose if:
- You want the lightest-weight option
- You are building in Go
- Simplicity is your top priority
Best Practices
Never Edit Applied Migrations
Once a migration has been applied to any environment, treat it as immutable. Create a new migration to fix issues in a previous migration. Editing applied migrations causes checksum mismatches and deployment failures.
Include Down Migrations (With Caveats)
Down migrations enable rollback, but not all changes are reversible. You cannot un-drop a column or un-delete data. Write down migrations for reversible changes (add column, create table, add index) and clearly document when a migration is not reversible.
Review Migrations Like Code
Database migrations change production data structures. Review them with the same rigor as application code. Check for:
- Missing indexes on columns used in WHERE clauses or JOINs
- Nullable columns that should have defaults
- Table locks from operations on large tables (add column with default in older PostgreSQL)
- Data migrations that could timeout on large datasets
Test Migrations Against Production-Sized Data
A migration that runs in milliseconds on a development database with 100 rows might lock a production table with 10 million rows for minutes. Test migrations against realistic data volumes before deploying to production.
Use Transactions
Wrap migrations in transactions when your database supports transactional DDL (PostgreSQL does, MySQL does not for most DDL). This ensures a failed migration does not leave the schema in a partially-applied state.
Database migrations are not glamorous, but getting them right is critical. A well-managed migration workflow prevents the 3 AM "the deployment broke the database" incidents that no developer wants to deal with.