Schema migration tools that replace Liquibase changelogs, from Encore's migrations applied on run and deploy to Flyway, Atlas, golang-migrate, Sqitch and dbmate, with what each one does differently.

Liquibase tracks schema changes as changesets in XML, YAML, JSON or SQL changelogs, records them in a DATABASECHANGELOG table, and can generate rollbacks, which is why it became the default in many Java shops. Teams start looking elsewhere when the changelog format feels heavier than the SQL it wraps, when migrations become a CI step that has to reach a private database, or after Liquibase Community 5.0 moved from Apache 2.0 to the Functional Source License in September 2025.
This guide compares the main alternatives, starting with Encore, which applies migrations as part of running and deploying the app, then Flyway, Atlas, golang-migrate, Sqitch and dbmate.
Encore combines an open source infrastructure SDK with a platform that provisions and deploys into your own AWS or GCP account. A database is declared in the TypeScript or Go service that uses it with a folder of numbered SQL migrations, and Encore applies new ones whenever the app runs locally and on every deploy, tracking them in a schema_migrations table, as described in the schema migrations docs. There is no migration step to add to CI and no network path to open into a private database, because the deploy runs migrations from inside your environment.
Run in your terminal to get started locally.
-- users/migrations/1_create_users.up.sql
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- users/migrations/2_add_last_login.up.sql
ALTER TABLE users ADD COLUMN last_login_at TIMESTAMPTZ;
CREATE INDEX users_last_login_idx ON users (last_login_at);
// users/users.go
package users
import (
"context"
"encore.dev/storage/sqldb"
)
// Migrations in ./migrations run on `encore run` and on every deploy.
var db = sqldb.NewDatabase("users", sqldb.DatabaseConfig{
Migrations: "./migrations",
})
type TouchParams struct {
Email string `json:"email"`
}
//encore:api private method=POST path=/users/login
func Touch(ctx context.Context, p *TouchParams) error {
_, err := db.Exec(ctx, `UPDATE users SET last_login_at = now() WHERE email = $1`, p.Email)
return err
}
encore run starts Postgres locally and applies both files before the first request, so every developer has the schema the code expects, and every preview environment gets it on deploy. On deploy, migrations are applied before the new code starts, and the docs ask for the old code to keep working against the new schema during the rollout, which is the same expand-and-contract discipline any zero-downtime migration needs. Encore uses the golang-migrate file format, so existing golang-migrate folders move across as they are, and tools such as Atlas can generate the files, as shown in the Atlas and GORM guide.
An AI coding agent that adds a column writes the migration file and the query that uses it in the same change, runs both against the local Postgres, and the reviewer sees the schema change next to the code. The database itself comes from the same declaration, as RDS on AWS or Cloud SQL on GCP in your account.
Migrations run against an isolated database in encore test, per the test infrastructure docs, and production SQL databases have deletion protection enabled at the cloud provider level, as the infrastructure management docs state. Pointing Encore at a database that already exists is covered in the existing database docs.
Best fit: TypeScript and Go teams who want migrations that run with the app locally and on deploy, next to a database provisioned in their own cloud account.
Flyway, now part of Redgate, applies versioned SQL files named V1__create_users.sql, V2__add_last_login.sql in order and records them in a flyway_schema_history table, with repeatable migrations (R__views.sql) for views and functions. It runs from a CLI, Maven or Gradle plugins, a Docker image, or the Java API at application startup. The open source Community edition covers versioned migrations, while undo migrations, dry runs and drift reports sit in the paid editions.
Best fit: Java and JVM teams leaving Liquibase who want plain SQL and the smallest conceptual change.
AtlasAtlas treats the desired schema as code, in HCL, SQL or an ORM's models, and generates migration files by diffing it against the migration directory with atlas migrate diff. Its linter flags destructive or locking changes, such as adding a non-null column without a default, before they merge, and it can check for drift between environments. Atlas also works as a generator for other tools' formats, including golang-migrate and Flyway.
Best fit: Teams that want declarative schemas with generated migrations and automated safety checks in pull requests.
golang-migrate is a CLI and Go library that applies paired N_name.up.sql and N_name.down.sql files and tracks a single version in a schema_migrations table. It supports many databases and sources, including files embedded in the binary. If a migration fails midway the table is marked dirty and needs migrate force before anything else runs, which is the main operational surprise.
Best fit: Go services that want a small, scriptable tool and already run migrations as a CI or deploy step.
Sqitch organizes changes by name and dependency rather than by number, with a plan file and separate deploy, revert and verify scripts for each change. The verify scripts check that a change actually did what it should, which few other tools offer. It suits teams that write a lot of database-side logic and want explicit dependencies between changes.
Best fit: Database-heavy projects with stored procedures and views, where dependency order matters more than version numbers.
dbmate is a single binary that keeps up and down sections in one SQL file, creates the database if needed, and can dump the schema to a schema.sql file after each migration for review. It is language-agnostic and reads the connection from DATABASE_URL.
Best fit: Polyglot teams that want one simple tool across services in different languages.
Pick Encore when the backend is TypeScript or Go and migrations should run with the app locally and on every deploy, against Postgres provisioned in your own AWS or GCP account. Pick Flyway for the closest SQL-first replacement in a JVM stack, Atlas for declarative schemas and migration linting, golang-migrate or dbmate for a small CLI step, and Sqitch when changes depend on each other by name.
For teams that want plain SQL files applied in order, Flyway and golang-migrate are the closest replacements. Atlas suits teams that want a declarative schema with generated migrations and linting.
Yes. Starting with Liquibase Community 5.0 in September 2025, the license moved from Apache 2.0 to the Functional Source License (FSL-1.1-ALv2). Production use stays free, third parties cannot offer it commercially in competition with Liquibase, and each release converts to Apache 2.0 two years after it ships.
Each database has a migrations folder of numbered files such as 1_create_users.up.sql and 2_add_index.up.sql. encore run applies new migrations to the local Postgres, and each deploy applies them before the new code starts, tracking applied versions in a schema_migrations table.
Flyway is simpler: versioned SQL files named like V2__add_index.sql applied in order, with a history table. Liquibase adds database-agnostic changelogs in XML, YAML or JSON, preconditions and generated rollbacks. Teams that write SQL directly usually find Flyway easier, and teams that target several database engines with one changelog lean toward Liquibase.
Deploy to your cloud on AWS and Google Cloud
without managing infrastructure
Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.