Declarative schema migrations with schema-as-code workflows
8,700
stars
2,709
commits
Go
primary language
Sep 4, 2026
updated
Atlas is a language-agnostic tool for managing and migrating database schemas using modern DevOps principles. It offers two workflows:
Declarative: Similar to Terraform, Atlas compares the current state of the database to the desired state, as defined in an HCL, SQL, or ORM schema. Based on this comparison, it generates and executes a migration plan to transition the database to its desired state.
Versioned: Unlike other tools, Atlas automatically plans schema migrations for you. Users can describe their desired database schema in HCL, SQL, or their chosen ORM, and by utilizing Atlas, they can plan, lint, and apply the necessary migrations to the database.
PostgreSQL · MySQL · MariaDB · SQL Server · SQLite · ClickHouse · Redshift · Oracle · Snowflake · CockroachDB · TiDB · Databricks · Spanner · Aurora DSQL · Azure Fabric
macOS + Linux:
curl -sSf https://atlasgo.sh | sh
Homebrew:
brew install ariga/tap/atlas
Docker:
docker pull arigaio/atlas
NPM:
npx @ariga/atlas
See installation docs for all platforms.
atlas schema command offers various options for inspecting, diffing, comparing, planning and applying migrations using standard Terraform-like workflows.atlas migrate command provides a state-of-the-art experience for planning, linting, and applying migrations.Get started with Atlas by following the Getting Started docs.
Inspect an existing database schema:
atlas schema inspect -u "postgres://localhost:5432/mydb"
Apply your desired schema to the database:
atlas schema apply \
--url "postgres://localhost:5432/mydb" \
--to file://schema.hcl \
--dev-url "docker://postgres/16/dev"
Atlas ships with 50+ built-in analyzers that review your migration files and catch issues before they reach production. Analyzers detect destructive changes like dropped tables or columns, data-dependent modifications such as adding non-nullable columns without defaults, and database-specific risks like table locks and table rewrites that can cause downtime on busy tables. You can also define your own custom policy rules.
atlas migrate lint --dev-url "docker://postgres/16/dev"
Test database logic (functions, views, triggers, procedures) and
data migrations with .test.hcl files:
test "schema" "postal" {
# Valid postal codes pass
exec {
sql = "SELECT '12345'::us_postal_code"
}
# Invalid postal codes fail
catch {
sql = "SELECT 'hello'::us_postal_code"
}
}
test "schema" "seed" {
for_each = [
{input: "hello", expected: "HELLO"},
{input: "world", expected: "WORLD"},
]
exec {
sql = "SELECT upper('${each.value.input}')"
output = each.value.expected
}
}
atlas schema test --dev-url "docker://postgres/16/dev"
Manage database roles, permissions, and row-level security as version-controlled code:
role "app_readonly" {
comment = "Read-only access for reporting"
}
role "app_writer" {
comment = "Read-write access for the application"
member_of = [role.app_readonly]
}
user "api_user" {
password = var.api_password
conn_limit = 20
comment = "Application API service account"
member_of = [role.app_writer]
}
permission {
for_each = [table.orders, table.products, table.users]
for = each.value
to = role.app_readonly
privileges = [SELECT]
}
policy "tenant_isolation" {
on = table.orders
for = ALL
to = ["app_writer"]
using = "(tenant_id = current_setting('app.current_tenant')::integer)"
check = "(tenant_id = current_setting('app.current_tenant')::integer)"
}
Manage seed and lookup data declaratively alongside your schema:
CREATE TABLE countries (
id INT PRIMARY KEY,
code VARCHAR(2) NOT NULL,
name VARCHAR(100) NOT NULL
);
INSERT INTO countries (id, code, name) VALUES
(1, 'US', 'United States'),
(2, 'IL', 'Israel'),
(3, 'DE', 'Germany');
Define your schema in any of the 16 supported ORMs. Atlas reads your models and generates migrations:
| Language | ORMs |
|---|---|
| Go | GORM, Ent, Bun, Beego, sqlc |
| TypeScript | Prisma, Drizzle, TypeORM, Sequelize |
| Python | Django, SQLAlchemy |
| Java | Hibernate |
| .NET | EF Core |
| PHP | Doctrine |
Lint, test, and apply migrations automatically in your CI/CD pipeline or infrastructure-as-code workflow:
| Integration | Docs |
|---|---|
| GitHub Actions | Versioned guide · Declarative guide |
| GitLab CI | Versioned guide · Declarative guide |
| CircleCI | Versioned guide · Declarative guide |
| Bitbucket Pipes | Versioned guide · Declarative guide |
| Azure DevOps | GitHub repos · Azure repos |
| Terraform Provider | atlasgo.io/integrations/terraform-provider |
| Kubernetes Operator | atlasgo.io/integrations/kubernetes |
| ArgoCD | atlasgo.io/guides/deploying/k8s-argo |
| Flux | atlasgo.io/guides/deploying/k8s-flux |
| Crossplane | atlasgo.io/guides/deploying/crossplane |
| Go SDK | pkg.go.dev/ariga.io/atlas-go-sdk/atlasexec |
Atlas provides Agent Skills, an open standard for packaging migration expertise for AI coding assistants: Claude Code, GitHub Copilot, Cursor, OpenAI Codex. Learn more at AI tools docs.
schema inspectEasily inspect your database schema by providing a database URL and convert it to HCL, JSON, SQL, ERD, or other formats.
Inspect a specific MySQL schema and get its representation in Atlas DDL syntax:
atlas schema inspect -u "mysql://root:pass@localhost:3306/example" > schema.hcl
table "users" {
schema = schema.example
column "id" {
null = false
type = int
}
...
}
Inspect the entire MySQL database and get its JSON representation:
atlas schema inspect \
--url "mysql://root:pass@localhost:3306/" \
--format '{{ json . }}' | jq
{
"schemas": [
{
"name": "example",
"tables": [
{
"name": "users",
"columns": [
...
]
}
]
}
]
}
Inspect a specific PostgreSQL schema and get its ERD representation in Mermaid syntax:
atlas schema inspect \
--url "postgres://root:pass@:5432/test?search_path=public&sslmode=disable" \
--format '{{ mermaid . }}'
erDiagram
users {
int id PK
varchar name
}
blog_posts {
int id PK
varchar title
text body
int author_id FK
}
blog_posts }o--o| users : author_fk
Use the split format for one-file-per-object output:
atlas schema inspect -u '<url>' --format '{{ sql . | split | write }}'
├── schemas
│ └── public
│ ├── public.sql
│ ├── tables
│ │ ├── profiles.sql
│ │ └── users.sql
│ ├── functions
│ └── types
└── main.sql
schema diffCompare two schema states and get a migration plan to transform one into the other. A state can be specified using a database URL, HCL, SQL, or ORM schema, or a migration directory.
atlas schema diff \
--from "postgres://postgres:pass@:5432/test?search_path=public&sslmode=disable" \
--to file://schema.hcl \
--dev-url "docker://postgres/15/test"
schema applyGenerate a migration plan and apply it to the database to bring it to the desired state. The desired state can be specified using a database URL, HCL, SQL, or ORM schema, or a migration directory.
atlas schema apply \
--url mysql://root:pass@:3306/db1 \
--to file://schema.hcl \
--dev-url docker://mysql/8/db1
-- Planned Changes:
-- Modify "users" table
ALTER TABLE `db1`.`users` DROP COLUMN `d`, ADD COLUMN `c` int NOT NULL;
Use the arrow keys to navigate: ↓ ↑ → ←
? Are you sure?:
▸ Apply
Abort
migrate diffWrite a new migration file to the migration directory that brings it to the desired state. The desired state can be specified using a database URL, HCL, SQL, or ORM schema, or a migration directory.
atlas migrate diff add_blog_posts \
--dir file://migrations \
--to file://schema.hcl \
--dev-url docker://mysql/8/test
migrate applyApply all or part of pending migration files in the migration directory on the database.
atlas migrate apply \
--url mysql://root:pass@:3306/db1 \
--dir file://migrations
To ensure the best performance, security and compatibility with the Atlas Cloud service, the Atlas team
will only support the two most recent minor versions of the CLI. For example, if the latest version is
v0.25, the supported versions will be v0.24 and v0.25 (in addition to any patch releases and the
"canary" release which is built twice a day).
Go
98.5%
ANTLR
1.0%
Declarative schema migrations with schema-as-code workflows
8,700
stars
2,709
commits
Go
primary language
Sep 4, 2026
updated
Atlas is a language-agnostic tool for managing and migrating database schemas using modern DevOps principles. It offers two workflows:
Declarative: Similar to Terraform, Atlas compares the current state of the database to the desired state, as defined in an HCL, SQL, or ORM schema. Based on this comparison, it generates and executes a migration plan to transition the database to its desired state.
Versioned: Unlike other tools, Atlas automatically plans schema migrations for you. Users can describe their desired database schema in HCL, SQL, or their chosen ORM, and by utilizing Atlas, they can plan, lint, and apply the necessary migrations to the database.
PostgreSQL · MySQL · MariaDB · SQL Server · SQLite · ClickHouse · Redshift · Oracle · Snowflake · CockroachDB · TiDB · Databricks · Spanner · Aurora DSQL · Azure Fabric
macOS + Linux:
curl -sSf https://atlasgo.sh | sh
Homebrew:
brew install ariga/tap/atlas
Docker:
docker pull arigaio/atlas
NPM:
npx @ariga/atlas
See installation docs for all platforms.
atlas schema command offers various options for inspecting, diffing, comparing, planning and applying migrations using standard Terraform-like workflows.atlas migrate command provides a state-of-the-art experience for planning, linting, and applying migrations.Get started with Atlas by following the Getting Started docs.
Inspect an existing database schema:
atlas schema inspect -u "postgres://localhost:5432/mydb"
Apply your desired schema to the database:
atlas schema apply \
--url "postgres://localhost:5432/mydb" \
--to file://schema.hcl \
--dev-url "docker://postgres/16/dev"
Atlas ships with 50+ built-in analyzers that review your migration files and catch issues before they reach production. Analyzers detect destructive changes like dropped tables or columns, data-dependent modifications such as adding non-nullable columns without defaults, and database-specific risks like table locks and table rewrites that can cause downtime on busy tables. You can also define your own custom policy rules.
atlas migrate lint --dev-url "docker://postgres/16/dev"
Test database logic (functions, views, triggers, procedures) and
data migrations with .test.hcl files:
test "schema" "postal" {
# Valid postal codes pass
exec {
sql = "SELECT '12345'::us_postal_code"
}
# Invalid postal codes fail
catch {
sql = "SELECT 'hello'::us_postal_code"
}
}
test "schema" "seed" {
for_each = [
{input: "hello", expected: "HELLO"},
{input: "world", expected: "WORLD"},
]
exec {
sql = "SELECT upper('${each.value.input}')"
output = each.value.expected
}
}
atlas schema test --dev-url "docker://postgres/16/dev"
Manage database roles, permissions, and row-level security as version-controlled code:
role "app_readonly" {
comment = "Read-only access for reporting"
}
role "app_writer" {
comment = "Read-write access for the application"
member_of = [role.app_readonly]
}
user "api_user" {
password = var.api_password
conn_limit = 20
comment = "Application API service account"
member_of = [role.app_writer]
}
permission {
for_each = [table.orders, table.products, table.users]
for = each.value
to = role.app_readonly
privileges = [SELECT]
}
policy "tenant_isolation" {
on = table.orders
for = ALL
to = ["app_writer"]
using = "(tenant_id = current_setting('app.current_tenant')::integer)"
check = "(tenant_id = current_setting('app.current_tenant')::integer)"
}
Manage seed and lookup data declaratively alongside your schema:
CREATE TABLE countries (
id INT PRIMARY KEY,
code VARCHAR(2) NOT NULL,
name VARCHAR(100) NOT NULL
);
INSERT INTO countries (id, code, name) VALUES
(1, 'US', 'United States'),
(2, 'IL', 'Israel'),
(3, 'DE', 'Germany');
Define your schema in any of the 16 supported ORMs. Atlas reads your models and generates migrations:
| Language | ORMs |
|---|---|
| Go | GORM, Ent, Bun, Beego, sqlc |
| TypeScript | Prisma, Drizzle, TypeORM, Sequelize |
| Python | Django, SQLAlchemy |
| Java | Hibernate |
| .NET | EF Core |
| PHP | Doctrine |
Lint, test, and apply migrations automatically in your CI/CD pipeline or infrastructure-as-code workflow:
| Integration | Docs |
|---|---|
| GitHub Actions | Versioned guide · Declarative guide |
| GitLab CI | Versioned guide · Declarative guide |
| CircleCI | Versioned guide · Declarative guide |
| Bitbucket Pipes | Versioned guide · Declarative guide |
| Azure DevOps | GitHub repos · Azure repos |
| Terraform Provider | atlasgo.io/integrations/terraform-provider |
| Kubernetes Operator | atlasgo.io/integrations/kubernetes |
| ArgoCD | atlasgo.io/guides/deploying/k8s-argo |
| Flux | atlasgo.io/guides/deploying/k8s-flux |
| Crossplane | atlasgo.io/guides/deploying/crossplane |
| Go SDK | pkg.go.dev/ariga.io/atlas-go-sdk/atlasexec |
Atlas provides Agent Skills, an open standard for packaging migration expertise for AI coding assistants: Claude Code, GitHub Copilot, Cursor, OpenAI Codex. Learn more at AI tools docs.
schema inspectEasily inspect your database schema by providing a database URL and convert it to HCL, JSON, SQL, ERD, or other formats.
Inspect a specific MySQL schema and get its representation in Atlas DDL syntax:
atlas schema inspect -u "mysql://root:pass@localhost:3306/example" > schema.hcl
table "users" {
schema = schema.example
column "id" {
null = false
type = int
}
...
}
Inspect the entire MySQL database and get its JSON representation:
atlas schema inspect \
--url "mysql://root:pass@localhost:3306/" \
--format '{{ json . }}' | jq
{
"schemas": [
{
"name": "example",
"tables": [
{
"name": "users",
"columns": [
...
]
}
]
}
]
}
Inspect a specific PostgreSQL schema and get its ERD representation in Mermaid syntax:
atlas schema inspect \
--url "postgres://root:pass@:5432/test?search_path=public&sslmode=disable" \
--format '{{ mermaid . }}'
erDiagram
users {
int id PK
varchar name
}
blog_posts {
int id PK
varchar title
text body
int author_id FK
}
blog_posts }o--o| users : author_fk
Use the split format for one-file-per-object output:
atlas schema inspect -u '<url>' --format '{{ sql . | split | write }}'
├── schemas
│ └── public
│ ├── public.sql
│ ├── tables
│ │ ├── profiles.sql
│ │ └── users.sql
│ ├── functions
│ └── types
└── main.sql
schema diffCompare two schema states and get a migration plan to transform one into the other. A state can be specified using a database URL, HCL, SQL, or ORM schema, or a migration directory.
atlas schema diff \
--from "postgres://postgres:pass@:5432/test?search_path=public&sslmode=disable" \
--to file://schema.hcl \
--dev-url "docker://postgres/15/test"
schema applyGenerate a migration plan and apply it to the database to bring it to the desired state. The desired state can be specified using a database URL, HCL, SQL, or ORM schema, or a migration directory.
atlas schema apply \
--url mysql://root:pass@:3306/db1 \
--to file://schema.hcl \
--dev-url docker://mysql/8/db1
-- Planned Changes:
-- Modify "users" table
ALTER TABLE `db1`.`users` DROP COLUMN `d`, ADD COLUMN `c` int NOT NULL;
Use the arrow keys to navigate: ↓ ↑ → ←
? Are you sure?:
▸ Apply
Abort
migrate diffWrite a new migration file to the migration directory that brings it to the desired state. The desired state can be specified using a database URL, HCL, SQL, or ORM schema, or a migration directory.
atlas migrate diff add_blog_posts \
--dir file://migrations \
--to file://schema.hcl \
--dev-url docker://mysql/8/test
migrate applyApply all or part of pending migration files in the migration directory on the database.
atlas migrate apply \
--url mysql://root:pass@:3306/db1 \
--dir file://migrations
To ensure the best performance, security and compatibility with the Atlas Cloud service, the Atlas team
will only support the two most recent minor versions of the CLI. For example, if the latest version is
v0.25, the supported versions will be v0.24 and v0.25 (in addition to any patch releases and the
"canary" release which is built twice a day).
Go
98.5%
ANTLR
1.0%