Skip to main content

Import Existing Databases or Migrations

Atlas provides two ways to start managing existing databases or setups with versioned migrations:

  1. 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.
  2. 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
Choosing the Connection URL
  • Go to Inspect a Database or Inspect a Single Schema sections to learn more about the atlas schema inspect command. 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 --exclude option.

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>'
Command Explanation
  • The first argument "baseline" specifies the name of the migration to be created. Atlas will create a file named <timestamp>_baseline.sql in the migration directory.
  • The --to flag points to the desired state of the database schema, which is the src/ folder we created earlier.
  • The --dev-url flag 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:

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"

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>'
Command Explanation
  • The --baseline flag 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 --url flag specifies the connection URL to the target database where the migration will be applied.
  • The --dir flag can be used to specify the path to the migration directory. By default, it is file://migrations.
  • The --dry-run flag 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:

  • --from the URL to the migration directory to import, the format query parameter controls the migration directory format, e.g. file://migrations?format=flyway. Supported formats are atlas (default), golang-migrate, goose, flyway, liquibase and dbmate.
  • --to the URL of the migration directory to save imported migration files into, by default it is file://migrations.

Limitations

Importing an existing migration directory has some limitations:

Comments not directly preceding a SQL statement will get lost.

-- 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.

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.

-- +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`;

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.

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`)
);

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"

Reference

CLI Command Reference