Import Existing Databases or Migrations
Atlas provides two ways to start managing existing databases or setups with versioned migrations:
- Baseline an existing database: Generate an initial migration file that represents the current state of your live database, so Atlas can begin managing it going forward.
- Import existing migration directories: Convert migration folders from tools like Flyway, Liquibase, Goose, or golang-migrate into Atlas's native format.
The sections below go over both approaches in detail.
Importing an Existing Database
The process for importing an existing database into Atlas versioned migrations involves three steps:
1. Export Database to Code
Choose the language that will be used to define the desired schema state, such as SQL or HCL. Use the atlas schema inspect command to import the current database schema into code. This code represents the desired state of the database and can be tested, versioned, and modified going forward - just like IaC (Infrastructure as Code), but for your databases.
2. Generate a Baseline Migration
Create an initial baseline migration file that represents the current state of the database using the atlas migrate diff command. This migration file serves as the starting point for future migrations. It will not be applied to existing databases but will be marked as already applied.
3. Apply the Baseline Migration
Run the atlas migrate apply command to apply the migration to the database. On existing databases, the migration will be marked as applied without executing its statements. On new or empty databases, the migration will be executed in full.
Export Database to Code
The very basic first step to manage your database schemas as code, is to have the state of the database schema (i.e., desired state)
represented in code. Atlas allows defining the desired state in various formats, such as SQL,
HCL, ORM schema, or a database connection. But for the purpose of this guide, we will focus on exporting
the database schema to SQL format. The full document of the atlas schema inspect command can be found here.
By default, the inspection result is written to standard output. To save it into a folder in a structured way, we can use the
split and write functions as described in the Export Database Schema to Code document.
atlas schema inspect -u '<url>' --format '{{ sql . | split | write "src" }}'
At this stage, we expect to have a folder named src with the format of the example below:
├── tables
│ ├── profiles.sql
│ └── users.sql
├── functions
│ ├── tenant_config.sql
│ └── tenant_profile.sql
├── types
└── main.sql
- Go to Inspect a Database or Inspect a Single Schema
sections to learn more about the
atlas schema inspectcommand. The examples there can help you to set up the connection URL. - To exclude some objects from inspection, such as schemas, tables or views, check out the
--excludeoption.
Generate a Baseline Migration
Now that we have the current state of the database schema represented in code, we can create a baseline migration file that captures this state. This migration is called a baseline because it serves as the starting point for future migrations. For existing databases that already match this state (such as the one we just inspected), we do not want to apply this migration but only mark it as applied so future migrations can build on top of it. For new databases, this migration will be applied in full.
To generate the baseline migration, use the atlas migrate diff command. This command compares the
migrations directory (which does not exist yet and is therefore considered empty) with the desired state defined in the
src/ folder created in the previous step. The example below uses the --dev-url flag, which is used internally by
Atlas - You can learn more about it in the Dev Database document:
atlas migrate diff "baseline" \
--to "file://src" \
--dev-url '<dev-url>'
- The first argument
"baseline"specifies the name of the migration to be created. Atlas will create a file named<timestamp>_baseline.sqlin the migration directory. - The
--toflag points to the desired state of the database schema, which is thesrc/folder we created earlier. - The
--dev-urlflag specifies a dev-database connection that Atlas uses to compute the diff.
Examples
The examples below show how to generate a baseline migration for different databases:
- PostgreSQL
- MySQL
- MariaDB
- SQL Server
- ClickHouse
- SQLite
- Redshift
In case your schema is contained within a specific schema (e.g., public), specify the search_path query parameter in
the connection URL:
atlas migrate diff "baseline" \
--to "file://src" \
--dev-url "docker://postgres/16/dev?search_path=public"
If your schema is spanned across multiple schemas, or you manage database-level objects (like extensions), use a database-scoped URL:
atlas migrate diff "baseline" \
--to "file://src" \
--dev-url "docker://postgres/16/dev"
In case your schema is contained within a specific database (e.g., dev), use the database-scoped URL as shown below:
atlas migrate diff "baseline" \
--to "file://src" \
--dev-url "docker://mysql/8/dev"
If your schema is spanned across multiple databases, use a server-scoped URL as shown below:
atlas migrate diff "baseline" \
--to "file://src" \
--dev-url "docker://mysql/8"
atlas migrate diff "baseline" \
--to "file://src" \
--dev-url "docker://mariadb/latest/dev"
If your schema is contained within a specific schema (e.g., dbo), use the schema-scoped URL as shown below:
atlas migrate diff "baseline" \
--to "file://src" \
--dev-url "docker://sqlserver/2022-latest/dev?mode=schema"
If your schema is spanned across multiple schemas, use a database-scoped URL as shown below:
atlas migrate diff "baseline" \
--to "file://src" \
--dev-url "docker://sqlserver/2022-latest/dev?mode=database"
If your schema is contained within a specific database (e.g., dev), use the database-scoped URL as shown below:
atlas migrate diff "baseline" \
--to "file://src" \
--dev-url "docker://clickhouse/23.11/dev"
If your schema is spanned across multiple databases, use a server-scoped URL as shown below:
atlas migrate diff "baseline" \
--to "file://src" \
--dev-url "docker://clickhouse/23.11"
atlas migrate diff "baseline" \
--to "file://src" \
--dev-url "sqlite://file?mode=memory"
atlas migrate diff "baseline" \
--to "file://src" \
--dev-url "redshift://user:pass@redshift-cluster:5439/dev?search_path=public&sslmode=disable"
When the database URL is set to a specific schema (e.g., mysql://:3306/dev), the scope of the work done by Atlas
(inspection, diffing, planning, applying, etc.) is limited to one schema. As a result, DDL statements printed during
diffing or planning will be formatted without schema qualifiers and can be executed on any schema. e.g., table instead
of schema.table
However, if the database URL does not specify a schema (e.g., mysql://:3306/), Atlas operates on the selected schemas
(defaulting to all), and the generated DDL statements include schema qualifiers. e.g., schema.table instead of table.
Apply the Baseline Migration
Once the baseline migration file is created, we can apply it using the atlas migrate apply command. There are two cases:
for existing databases, we use the --baseline flag to set the database at this version, and for new (empty) databases,
Atlas runs the migration to create the initial schema.
Existing databases
For databases that already contain the schema we inspected, we don't want to execute the baseline migration again.
Instead, we mark it as already applied using the --baseline flag. This tells Atlas that the database is already at
the baseline version, so future migrations can be applied safely on top of it.
The --baseline flag accepts the migration version as an argument. The version is the timestamp portion from the
migration file name. For example, if your baseline migration file is named 20250811074144_baseline.sql, the version
to pass to the flag would be 20250811074144.
atlas migrate apply \
--url '<url>' \
--baseline '20250811074144'
New databases
For new or empty databases, Atlas will execute the baseline migration in full to create the schema from scratch.
atlas migrate apply --url '<url>'
- The
--baselineflag is used only for existing databases. It marks the current schema version without running the migration's SQL statements, ensuring Atlas recognizes the correct starting point for version tracking. - The
--urlflag specifies the connection URL to the target database where the migration will be applied. - The
--dirflag can be used to specify the path to the migration directory. By default, it isfile://migrations. - The
--dry-runflag can be used to preview the SQL statements that would be executed without actually applying them.
Video Tutorial
📺 For a step-by-step example walk-through, watch our 3-minute tutorial: Versioned Migrations for Existing Databases using Atlas
Importing Existing Migration Directories
Atlas supports the generation of custom migration file formats for a variety of existing migration management tools, e.g. Flyway or golang-migrate/migrate. But Atlas has its own format as well and provides a convenient command to import existing migration directories of supported tools into the Atlas format.
Flags
When using atlas migrate import to import a migration directory, users must supply multiple parameters:
--fromthe URL to the migration directory to import, theformatquery parameter controls the migration directory format, e.g.file://migrations?format=flyway. Supported formats areatlas(default),golang-migrate,goose,flyway,liquibaseanddbmate.--tothe URL of the migration directory to save imported migration files into, by default it isfile://migrations.
Limitations
Importing an existing migration directory has some limitations:
Comments not directly preceding a SQL statement will get lost.
- source.sql
- imported.sql
-- This comment will get lost
-- This will be preserved
/*
This will be preserved as well
/*
CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`age` bigint(20) NOT NULL,
`name` varchar(255) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `age` (`age`)
); -- This will get lost.
-- This will be preserved
/*
This will be preserved as well
/*
CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`age` bigint(20) NOT NULL,
`name` varchar(255) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `age` (`age`)
);
Rollback migrations will not get imported.
Atlas does not have the concept of rollback migrations. Therefore migrations to undo an applied migration, often called "down" or "undo" migrations, will not be imported into the new migration directory. For migration formats having the rollback migration part of one file separated by some directive, the rollback parts are stripped away.
- source.sql
- imported.sql
-- +goose Up
CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`age` bigint(20) NOT NULL,
`name` varchar(255) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `age` (`age`)
);
-- +goose Down
DROP TABLE `users`;
CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`age` bigint(20) NOT NULL,
`name` varchar(255) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `age` (`age`)
);
Repeatable Migrations
Flyway has the concept of repeatable migrations, however, Atlas does not. In Flyway repeatable migrations are run last,
if their contents did change. Atlas tries to reproduce this behavior by creating versioned migrations out of each
repeatable migration file found and giving them the character R as version suffix.
- V1__users.sql
- R__users_view.sql
- 1_users.sql
- 1R_users_view.sql
CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`age` bigint(20) NOT NULL,
`name` varchar(255) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `age` (`age`)
);
CREATE VIEW `users_over_30` AS SELECT * FROM `users` where `age` > 30;
CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`age` bigint(20) NOT NULL,
`name` varchar(255) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `age` (`age`)
);
CREATE VIEW `users_over_30` AS SELECT * FROM `users` where `age` > 30;
Examples
Import existing golang-migrate/migrate migration directory:
atlas migrate import \
--from "file://migrations?format=golang-migrate" \
--to "file://atlas-migrations"
Import existing Flyway migration directory:
atlas migrate import \
--from "file://migrations?format=flyway" \
--to "file://atlas-migrations"