Database Schema Migration Skill for AI Agents
Agent Skills are an open standard for packaging domain expertise for AI agents. Introduced by Anthropic and adopted by OpenAI Codex CLI, Cursor, and other coding agents, skills enable AI to perform specialized tasks using deterministic tooling.
AI agents can edit schema files the same way they edit code. But generating migrations is a different problem: migrations require understanding object dependencies and safe change ordering across the entire schema - tables, views, functions, triggers, and constraints all depend on each other. Schema changes must be validated before applying them, and they must follow organizational policies - naming conventions, compliance requirements, and team standards. Most importantly, migrations must be deterministic, and the same schema change should always produce the same migration, regardless of which model or prompt generated it.
This skill teaches AI agents to manage the entire migration lifecycle: from diff generation and migration creation, through linting and testing, to safe production deployment. It covers multi-dialect support (MySQL, PostgreSQL, SQLite, SQL Server, ClickHouse, and more) and integrates with ORMs like GORM, Drizzle, SQLAlchemy, Django, and more.
Installation
- OpenAI Codex CLI
- Claude
- Cursor
- Project-level
OpenAI Codex CLI supports skills natively. Create a skill directory and add the SKILL.md file:
mkdir -p ~/.codex/skills/atlas/references
---
name: atlas
description: "Database schema management and migrations with Atlas CLI. Use when: generating migrations, diffing schemas, linting or testing migrations, applying schema changes, inspecting databases, working with atlas.hcl, schema.hcl, or ORM schemas (GORM, Drizzle, SQLAlchemy, Django, Ent, Sequelize, TypeORM), validating schema definitions, or checking Atlas Cloud registry and deployment status."
---
# Atlas Schema Migrations
## Security
Never hardcode credentials. Use environment variables:
```hcl
env "prod" {
url = getenv("DATABASE_URL")
}
```
## Quick Reference
Use `--help` on any command for comprehensive docs and examples:
```bash
atlas migrate diff --help
```
Always use `--env` to reference configurations from `atlas.hcl` — this avoids passing
database credentials to the LLM context.
```bash
# Common
atlas schema inspect --env <name> # Inspect schema
atlas schema validate --env <name> # Validate schema syntax/semantics
atlas schema diff --env <name> # Compare schemas
atlas schema lint --env <name> # Check schema policies
atlas schema test --env <name> # Test schema
# Declarative workflow
atlas schema plan --env <name> # Plan schema changes
atlas schema apply --env <name> --dry-run # Preview changes
atlas schema apply --env <name> # Apply schema changes
# Versioned workflow
atlas migrate diff --env <name> "migration_name" # Generate migration
atlas migrate lint --env <name> --latest 1 # Validate migration
atlas migrate test --env <name> # Test migration
atlas migrate apply --env <name> --dry-run # Preview changes
atlas migrate apply --env <name> # Apply migration
atlas migrate status --env <name> # Check status
```
## Choosing a Workflow
```
Schema change needed
├─ Project has migrations/ dir or migration config in atlas.hcl?
│ ├─ Yes → Versioned: migrate diff → lint → test → apply
│ └─ No → Declarative: schema apply --dry-run → apply
├─ Iterating on local database?
│ └─ Use schema apply --auto-approve for fast edit-apply cycles
└─ Not sure → Read atlas.hcl first
```
**Tip:** `atlas schema apply` applies schema changes directly to a local database without generating migration files. This is useful for fast iteration during development — edit the schema, run `schema apply`, and see the result immediately.
## Example
```
User: Add an email column to the users table
Agent steps:
1. atlas schema inspect --env dev # understand current state
2. Edit schema source file # add email column
3. atlas schema validate --env dev # verify syntax
4. atlas migrate diff --env dev "add_email" # generate migration
5. atlas migrate lint --env dev --latest 1 # check for issues
6. atlas migrate apply --env dev --dry-run # preview before applying
```
## Core Concepts
### Configuration File (atlas.hcl)
Always read the project's `atlas.hcl` first — it contains environment configurations:
```hcl
env "<name>" {
url = getenv("DATABASE_URL")
dev = "docker://postgres/15/dev?search_path=public"
migration {
dir = "file://migrations"
}
schema {
src = "file://schema.hcl"
}
}
```
### Dev Database
Atlas uses a temporary "dev-database" to process and validate schemas. The URL format depends on whether you work with a **single schema** or **multiple schemas**:
```bash
# Schema-scoped (single schema — most common)
--dev-url "docker://mysql/8/dev"
--dev-url "docker://postgres/15/dev?search_path=public"
--dev-url "sqlite://dev?mode=memory"
--dev-url "docker://sqlserver/2022-latest/dev?mode=schema"
# Database-scoped (multiple schemas, extensions, or event triggers)
--dev-url "docker://mysql/8"
--dev-url "docker://postgres/15/dev"
--dev-url "docker://sqlserver/2022-latest/dev?mode=database"
```
**Important:** Using the wrong scope causes errors (`ModifySchema is not allowed`) or silently drops database-level objects (extensions, event triggers) from migrations. Match the dev URL scope to the project's target database URL. For PostGIS or pgvector schemas, use `docker://postgis/latest/dev` or `docker://pgvector/pg17/dev`.
If the schema depends on extensions or external objects, use a `docker` block with a `baseline`:
```hcl
docker "postgres" "dev" {
image = "postgres:15"
schema = "public"
baseline = <<SQL
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
SQL
}
env "local" {
src = "file://schema.hcl"
dev = docker.postgres.dev.url
}
```
## Workflows
### 1. Schema Inspection
Start with a high-level overview before diving into details. The default output is HCL.
Use `--format "{{ json . }}"` for JSON or `--format "{{ sql . }}"` for SQL.
```bash
# List tables (overview first, JSON output)
atlas schema inspect --env <name> --format "{{ json . }}" | jq ".schemas[].tables[].name"
# Full SQL schema
atlas schema inspect --env <name> --format "{{ sql . }}"
# Filter with --include/--exclude (useful for large schemas)
atlas schema inspect --env <name> --include "users_*" # Only matching tables
atlas schema inspect --env <name> --exclude "*_backup" # Skip matching tables
atlas schema inspect --env <name> --exclude "*[type=trigger]" # Skip triggers
# Open visual ERD in browser (requires atlas login)
atlas schema inspect --env <name> -w
```
### 2. Schema Comparison (Diff)
Compare any two schema states:
```bash
# Compare current state to desired schema
atlas schema diff --env <name>
# Compare specific sources
atlas schema diff --env <name> --from file://migrations --to file://schema.hcl
```
### 3. Migration Generation
Generate migrations from schema changes:
```bash
# Generate migration from schema diff
atlas migrate diff --env <name> "add_users_table"
# With explicit parameters
atlas migrate diff \
--dir file://migrations \
--dev-url docker://postgres/15/dev \
--to file://schema.hcl \
"add_users_table"
```
### 4. Schema Validation
Validate schema definitions before generating migrations:
```bash
# Validate schema syntax and semantics
atlas schema validate --env <name>
# Validate against dev database
atlas schema validate --dev-url docker://postgres/15/dev --url file://schema.hcl
```
If valid, exits successfully. If invalid, prints detailed error (unresolved references, syntax issues, unsupported attributes).
### 5. Migration Linting
```bash
atlas migrate lint --env <name> --latest 1 # Lint latest migration
atlas migrate lint --env ci # Lint since git branch
atlas schema lint --env <name> # Check schema policies
```
Fixing lint issues:
- Unapplied migrations: Edit file, then `atlas migrate hash --env <name>`
- Applied migrations: Create corrective migration (never edit directly)
### 6. Migration Testing
```bash
atlas migrate test --env <name> # Requires atlas login
atlas whoami # Check login status first
```
### 7. Applying Migrations
```bash
atlas migrate apply --env <name> --dry-run # Always preview first
atlas migrate apply --env <name> # Apply
atlas migrate status --env <name> # Verify
```
## Standard Workflow
1. `atlas schema inspect --env <name>` — Understand current state
2. Edit schema files
3. `atlas schema validate --env <name>` — Check syntax
4. `atlas migrate diff --env <name> "change_name"` — Generate migration
5. `atlas migrate lint --env <name> --latest 1` — Validate
6. `atlas migrate test --env <name>` — Test (requires login)
7. If issues: edit migration, then `atlas migrate hash`
8. `atlas migrate apply --env <name> --dry-run` then apply
## Schema Sources
For HCL schemas, ORM integrations (GORM, Drizzle, SQLAlchemy, Django, Ent, Sequelize, TypeORM),
composite schemas, and dev-database dialect URLs, see `references/schema-sources.md`.
## Atlas Cloud
For registry repos, registered database targets, deployment events, pre-flight checks, and
cloud vs local command guidance, see `references/cloud.md`.
## Onboarding an Existing Project
### Baseline an existing database
To start managing an existing database with versioned migrations:
```bash
# 1. Export current schema to code
atlas schema inspect -u '<database-url>' --format '{{ sql . | split | write "src" }}'
# 2. Generate a baseline migration from the exported schema
atlas migrate diff "baseline" --to "file://src" --dev-url '<dev-url>'
# 3. Mark baseline as applied on existing databases (use version from filename)
atlas migrate apply --url '<database-url>' --baseline '<version>'
```
The baseline migration captures the current state without executing it on existing databases.
On new databases, it runs in full to create the initial schema.
## Troubleshooting
```bash
# Check installation and login
atlas version
atlas whoami
# Repair migration integrity after manual edits
atlas migrate hash --env <name>
```
**Missing driver error**: Ensure `--url` or `--dev-url` is correctly specified.
## Key Rules
1. Read `atlas.hcl` first — use environment names from config
2. Never hardcode credentials — use `getenv()`
3. Run `atlas schema validate` after schema edits
4. Always lint before applying migrations
5. Always dry-run before applying
6. Run `atlas migrate hash` after editing migration files
7. Use `atlas login` to unlock views, triggers, functions, ERD, and migration testing
8. Write migration tests for data migrations
9. Never ignore lint errors — fix them or get user approval
10. Before production deploys, check Atlas Cloud state (`atlas cloud database list`, `migration list --status FAILED`) — see `references/cloud.md`
## Documentation
- [CLI Reference](https://atlasgo.io/cli-reference)
- [Versioned Migrations](https://atlasgo.io/versioned/diff)
- [Declarative Workflow](https://atlasgo.io/declarative/apply)
- [Migration Linting](https://atlasgo.io/versioned/lint)
- [Migration Testing](https://atlasgo.io/testing/migrate)
- [Onboard Existing Database](https://atlasgo.io/versioned/import)
- [ORM Integrations](https://atlasgo.io/guides/orms)
- [Dev Database](https://atlasgo.io/concepts/dev-database)
# Schema Sources Reference
## HCL Schema
```hcl
data "hcl_schema" "<name>" {
path = "schema.hcl"
}
env "<name>" {
schema {
src = data.hcl_schema.<name>.url
}
}
```
## External Schema (ORM Integration)
The `external_schema` data source imports SQL schema from an ORM or external program.
```hcl
# GORM (Go)
data "external_schema" "gorm" {
program = ["go", "run", "-mod=mod", "ariga.io/atlas-provider-gorm", "load", "--path", "./models", "--dialect", "postgres"]
}
# Drizzle (TypeScript)
data "external_schema" "drizzle" {
program = ["npx", "drizzle-kit", "export"]
}
# SQLAlchemy (Python)
data "external_schema" "sqlalchemy" {
program = ["python", "-m", "atlas_provider_sqlalchemy", "--path", "./models", "--dialect", "postgresql"]
}
# Django (Python)
data "external_schema" "django" {
program = ["python", "manage.py", "atlas-provider-django", "--dialect", "postgresql"]
}
# Ent (Go)
env "<name>" {
schema {
src = "ent://ent/schema"
}
}
# Sequelize (Node.js)
data "external_schema" "sequelize" {
program = ["npx", "@ariga/atlas-provider-sequelize", "load", "--path", "./models", "--dialect", "postgres"]
}
# TypeORM (TypeScript)
data "external_schema" "typeorm" {
program = ["npx", "@ariga/atlas-provider-typeorm", "load", "--path", "./entities", "--dialect", "postgres"]
}
```
Wire into an environment:
```hcl
env "<name>" {
schema {
src = data.external_schema.<orm>.url
}
}
```
## Composite Schema (Pro)
Combine multiple schema sources into one:
```hcl
data "composite_schema" "app" {
schema "users" {
url = data.external_schema.auth_service.url
}
schema "graph" {
url = "ent://ent/schema"
}
schema "shared" {
url = "file://schema/shared.hcl"
}
}
```
## Dev-Database Dialects
The dev URL format depends on whether your project uses **schema-scoped** or **database-scoped** migrations. Getting this wrong causes errors like `ModifySchema is not allowed` or silently drops database-level objects (extensions, event triggers) from migrations.
**Schema-scoped** (single schema — most common): include the database name and schema scope so Atlas creates objects in the correct schema. Use this when all tables live in one schema (e.g., `public`).
| Dialect | Dev URL (schema-scoped) |
|------------|------------------------------------------------------|
| MySQL | `docker://mysql/8/dev` |
| MariaDB | `docker://maria/latest/dev` |
| PostgreSQL | `docker://postgres/17/dev?search_path=public` |
| SQLite | `sqlite://dev?mode=memory` |
| SQL Server | `docker://sqlserver/2022-latest/dev?mode=schema` |
| ClickHouse | `docker://clickhouse/23.11/dev` |
**Database-scoped** (multiple schemas or database-level objects): omit the schema scope so Atlas can manage multiple schemas and detect database-level objects like extensions and event triggers.
| Dialect | Dev URL (database-scoped) |
|------------|------------------------------------------------------|
| MySQL | `docker://mysql/8` |
| MariaDB | `docker://maria/latest` |
| PostgreSQL | `docker://postgres/17/dev` |
| SQL Server | `docker://sqlserver/2022-latest/dev?mode=database` |
| ClickHouse | `docker://clickhouse/23.11` |
**PostgreSQL with extensions** — use PostGIS or pgvector images when the schema uses those extensions:
```
docker://postgis/latest/dev?search_path=public
docker://pgvector/pg17/dev?search_path=public
```
**How to choose:** Check the project's `atlas.hcl` or target database URL. If it includes `search_path=public` (Postgres) or a specific database name (MySQL), use schema-scoped. If the project manages multiple schemas, extensions, or event triggers, use database-scoped.
See https://atlasgo.io/concepts/dev-database for additional drivers and options.
# Atlas Cloud CLI
`atlas cloud` commands read and manage resources in **Atlas Cloud** (the Atlas Registry and deployment tracking). They do **not** connect to databases directly — they report what Atlas Cloud knows about repos, registered databases (targets), and deployment events.
Use them for **operational visibility** and **pre-flight checks**. Use local commands (`atlas migrate status`, `atlas migrate apply`, `atlas schema diff`) to inspect or change an actual database.
## Prerequisites
1. **Atlas CLI** — `atlas cloud` is not only available in the community version.
2. **Authentication** — run before any cloud command:
```bash
atlas whoami # verify current org
atlas login [org] # interactive login
atlas login --token "$TOKEN" # CI / non-interactive
```
`ATLAS_TOKEN` env var is also accepted by `atlas login`.
3. If `atlas whoami` fails, stop and authenticate before proceeding.
## Command Reference
```
atlas cloud
├── repo
│ ├── list
│ ├── describe
│ ├── create
│ └── lingraph
├── database
│ ├── list
│ └── describe
└── migration
├── list
└── describe
```
### `atlas cloud repo`
Manage Atlas Registry repositories (schema or migration directory artifacts).
| Command | Purpose |
|---------|---------|
| `repo list` | List all repos with per-repo database counts (synced / failed / pending) |
| `repo describe` | Details for one repo: slug, type, driver, URL, database counts |
| `repo create` | Create an empty repo in the registry (before first push); idempotent if the repo already exists |
| `repo lingraph` | Print the migration lineage graph for a repo |
**Identify a repo** (describe): exactly one of `--id`, `--slug`, or `--name`.
**Create flags** (all required):
- `--type schema` (or `s`) — declarative schema repo
- `--type migration_directory` (or `m`) — versioned migration repo
- `--name <name>` — repo name
- `--driver <driver>` — e.g. `postgres`, `mysql`, `sqlite`, `mssql`, `clickhouse`, `cockroach`
**Lineage graph**:
```bash
atlas cloud repo lingraph --slug <slug>
atlas cloud repo lingraph --slug <slug> --open-lineage # OpenLineage format
```
### `atlas cloud database`
Query **registered migration/schema targets** (databases linked to Atlas Cloud).
| Command | Purpose |
|---------|---------|
| `database list` | List all cloud-tracked databases |
| `database describe` | Details for one database |
**Output fields**: `ID`, `Name`, `RepoName`, `EnvName`, `Status`, `CurrentVersion`, `LastDeploymentTime`.
**Database status** (`Status` column):
| Status | Meaning |
|--------|---------|
| `SYNCED` | Target matches the expected repo version |
| `PENDING` | Deployment or sync is in progress / not yet complete |
| `FAILED` | Last sync or deployment failed for this target |
**Filters** (list):
- `--env-name <env>` — filter by environment name (matches `env` blocks in `atlas.hcl`)
**Identify a database** (describe): exactly one of `--id` or `--ext-id`.
### `atlas cloud migration`
Query **deployment events** (each time migrations or schema were applied to targets).
| Command | Purpose |
|---------|---------|
| `migration list` | List deployment events with filters |
| `migration describe` | Details for one event |
**Migration event status**:
| Status | Meaning |
|--------|---------|
| `PASSED` | Deployment succeeded |
| `FAILED` | Deployment failed |
| `NO_ACTION` | No changes were needed |
| `DRY_RUN` | Dry-run only, nothing applied |
**Filters** (list):
- `--status <status>` — repeatable; values: `PASSED`, `FAILED`, `NO_ACTION`, `DRY_RUN`
- `--repo <slug>` — filter by repository slug
- `--name <substring>` — filter by database name (contains match)
- `--env-name <env>` — filter by environment
**Describe**: `--id <migration-event-id>` (required).
## Common Flags
| Flag | Commands | Purpose |
|------|----------|---------|
| `--format <template>` | list, describe (except lingraph) | Go template output; use `json` helper for machine-readable — `--format '{{json .}}'` |
| `--page <n>` | list commands | Page number to fetch (default 1); see **Pagination** below |
### Pagination
List commands (`repo list`, `database list`, `migration list`) return at most **20 records per page**. Each response ends with a footer:
```
--------------------------------
Page: 1 Page Size: 20 Total: 45
```
| Footer field | Meaning |
|--------------|---------|
| `Page` | Current page (1-based); matches the `--page` flag value |
| `Page Size` | Fixed at 20 records per page (not configurable via CLI) |
| `Total` | Total records matching the current filters across all pages |
**Are there more pages?** When `Total > Page Size` (i.e. `Total > 20`). Compute the number of pages:
```
total_pages = ceil(Total / Page Size)
```
Example: `Total: 45`, `Page Size: 20` → `ceil(45 / 20) = 3` pages.
**When to fetch the next page:**
- If `Page < total_pages`, more records exist — re-run the same command with `--page <Page + 1>`.
- If `Page == total_pages`, you have all records for the current filters.
- If `Total <= Page Size`, everything fits on one page; no further requests needed.
**Example** (45 records across 3 pages):
```bash
atlas cloud database list # page 1: records 1–20
atlas cloud database list --page 2 # page 2: records 21–40
atlas cloud database list --page 3 # page 3: records 41–45
```
With `--format '{{ json . }}'`, pagination metadata is on the `PageInfo` field (`Page`, `PageSize`, `Total`). Use it in scripts to decide whether to request another page.
**Examples**:
```bash
atlas cloud database list
atlas cloud migration list --status FAILED
```
## When to Use Which Command
| User goal | Start with |
|-----------|------------|
| Is a repo healthy across all its databases? | `atlas cloud repo list` or `repo describe --slug <slug>` |
| What version is a database on in Atlas Cloud? | `atlas cloud database list --env-name <env>` or `database describe` |
| Did a recent deployment fail? | `atlas cloud migration list --status FAILED` |
| What happened in a specific deployment? | `atlas cloud migration describe --id <id>` |
| Create a registry repo before first push | `atlas cloud repo create --type m --name <n> --driver postgres` |
| Check object dependencies | `atlas cloud repo lingraph --slug <slug>` |
| Which org am I connected to? | `atlas whoami` |
| Can I push a schema change or migration to database X? | `atlas cloud database list` then `atlas cloud database describe --id <id>` using the id of database X from the list |
## Agent Workflows
### Pre-deployment readiness
Before recommending `atlas migrate apply` or a CI deploy, check Atlas Cloud state:
```
Task Progress:
- [ ] Verify auth: atlas whoami
- [ ] Check target status: atlas cloud database list --env-name <env>
- [ ] Check for failed deployments: atlas cloud migration list --status FAILED --env-name <env>
- [ ] Check repo health: atlas cloud repo describe --slug <slug>
```
**Decision rules**:
- Any database with `Status=FAILED` → investigate before applying. Run `migration list --status FAILED` filtered to that env/repo, then `migration describe` on the event ID.
- Any database with `Status=PENDING` → a deployment may be in flight; wait or confirm before starting another.
- All targets `SYNCED` and no recent `FAILED` events → cloud state looks healthy. Still run local checks (`atlas migrate status`, lint) before applying.
- `repo describe` shows `Databases Failed > 0` → at least one target in that repo is unhealthy; drill into `database list` and `migration list`.
### Investigate a failed deployment
1. `atlas cloud migration list --status FAILED --repo <slug>` (add `--env-name` or `--name` to narrow)
2. `atlas cloud migration describe --id <id>` for version, completion time, and multi-target results
3. `atlas cloud database describe --id <id>` on affected targets to see current version vs expected
4. Use local `atlas migrate status --env <env>` to compare the live database revision table against cloud state
### Audit environments
Read `atlas.hcl` first to find environment names (`env` block names). For each environment you want to compare, run:
```bash
atlas cloud database list --env-name <env>
atlas cloud migration list --env-name <env>
```
Repeat for every relevant `env` in the project (e.g. dev, staging, prod — names vary). Compare `CurrentVersion` across environments to spot version skew.
### Set up a new registry repo
1. `atlas cloud repo create --type migration_directory --name <name> --driver postgres`
2. Note the returned `Slug` and `URL`
3. Reference in `atlas.hcl`: `migration { dir = "atlas://<slug>" }`
4. Push migrations with `atlas migrate push` (separate from `atlas cloud`)
## Cloud vs Local Commands
| Concern | Atlas Cloud (`atlas cloud …`) | Local (`atlas migrate/schema …`) |
|---------|-------------------------------|-----------------------------------|
| Registry repos & artifacts | ✅ | `migrate push`, `schema push` |
| Registered target status | ✅ | — |
| Deployment event history | ✅ | — |
| Live database revision table | — | `migrate status` |
| Schema drift vs desired state | — | `schema diff`, `migrate lint` |
| Apply changes to a database | — | `migrate apply`, `schema apply` |
Cloud commands answer **"what does Atlas Cloud know?"** Local commands answer **"what is actually in the database?"** Use both when validating readiness.
## Reporting Results to the User
When summarizing cloud command output:
1. State the org (`atlas whoami`) and filters used
2. Highlight `FAILED` / `PENDING` statuses prominently
3. For migrations, include `Version`, `Status`, `CompletedAt`, and `TargetsSucceeded/TargetsTotal` when present
4. Distinguish cloud-reported state from local database state — recommend local verification when the user plans to apply changes
5. For list commands, read the pagination footer (or `PageInfo` in JSON). If `Total > Page Size`, compute `total_pages = ceil(Total / Page Size)` and fetch remaining pages with `--page 2`, `--page 3`, etc. until `Page == total_pages` before concluding the result set is complete
## Error Handling
| Error | Action |
|-------|--------|
| `'atlas login' is required` | Run `atlas login` or set token |
| `repository not found` / `database not found` / `migration not found` | Verify identifier; try `list` first to get correct ID/slug |
| `invalid --status value` | Use `PASSED`, `FAILED`, `NO_ACTION`, or `DRY_RUN` |
| `invalid --type` | Use `schema`/`s` or `migration_directory`/`m` |
| Mutually exclusive flags (`--id` vs `--slug`) | Provide exactly one identifier |
Codex will automatically load the skill when database operations are requested.
Create a skill directory and add the SKILL.md file:
mkdir -p ~/.claude/skills/atlas/references
---
name: atlas
description: "Database schema management and migrations with Atlas CLI. Use when: generating migrations, diffing schemas, linting or testing migrations, applying schema changes, inspecting databases, working with atlas.hcl, schema.hcl, or ORM schemas (GORM, Drizzle, SQLAlchemy, Django, Ent, Sequelize, TypeORM), validating schema definitions, or checking Atlas Cloud registry and deployment status."
---
# Atlas Schema Migrations
## Security
Never hardcode credentials. Use environment variables:
```hcl
env "prod" {
url = getenv("DATABASE_URL")
}
```
## Quick Reference
Use `--help` on any command for comprehensive docs and examples:
```bash
atlas migrate diff --help
```
Always use `--env` to reference configurations from `atlas.hcl` — this avoids passing
database credentials to the LLM context.
```bash
# Common
atlas schema inspect --env <name> # Inspect schema
atlas schema validate --env <name> # Validate schema syntax/semantics
atlas schema diff --env <name> # Compare schemas
atlas schema lint --env <name> # Check schema policies
atlas schema test --env <name> # Test schema
# Declarative workflow
atlas schema plan --env <name> # Plan schema changes
atlas schema apply --env <name> --dry-run # Preview changes
atlas schema apply --env <name> # Apply schema changes
# Versioned workflow
atlas migrate diff --env <name> "migration_name" # Generate migration
atlas migrate lint --env <name> --latest 1 # Validate migration
atlas migrate test --env <name> # Test migration
atlas migrate apply --env <name> --dry-run # Preview changes
atlas migrate apply --env <name> # Apply migration
atlas migrate status --env <name> # Check status
```
## Choosing a Workflow
```
Schema change needed
├─ Project has migrations/ dir or migration config in atlas.hcl?
│ ├─ Yes → Versioned: migrate diff → lint → test → apply
│ └─ No → Declarative: schema apply --dry-run → apply
├─ Iterating on local database?
│ └─ Use schema apply --auto-approve for fast edit-apply cycles
└─ Not sure → Read atlas.hcl first
```
**Tip:** `atlas schema apply` applies schema changes directly to a local database without generating migration files. This is useful for fast iteration during development — edit the schema, run `schema apply`, and see the result immediately.
## Example
```
User: Add an email column to the users table
Agent steps:
1. atlas schema inspect --env dev # understand current state
2. Edit schema source file # add email column
3. atlas schema validate --env dev # verify syntax
4. atlas migrate diff --env dev "add_email" # generate migration
5. atlas migrate lint --env dev --latest 1 # check for issues
6. atlas migrate apply --env dev --dry-run # preview before applying
```
## Core Concepts
### Configuration File (atlas.hcl)
Always read the project's `atlas.hcl` first — it contains environment configurations:
```hcl
env "<name>" {
url = getenv("DATABASE_URL")
dev = "docker://postgres/15/dev?search_path=public"
migration {
dir = "file://migrations"
}
schema {
src = "file://schema.hcl"
}
}
```
### Dev Database
Atlas uses a temporary "dev-database" to process and validate schemas. The URL format depends on whether you work with a **single schema** or **multiple schemas**:
```bash
# Schema-scoped (single schema — most common)
--dev-url "docker://mysql/8/dev"
--dev-url "docker://postgres/15/dev?search_path=public"
--dev-url "sqlite://dev?mode=memory"
--dev-url "docker://sqlserver/2022-latest/dev?mode=schema"
# Database-scoped (multiple schemas, extensions, or event triggers)
--dev-url "docker://mysql/8"
--dev-url "docker://postgres/15/dev"
--dev-url "docker://sqlserver/2022-latest/dev?mode=database"
```
**Important:** Using the wrong scope causes errors (`ModifySchema is not allowed`) or silently drops database-level objects (extensions, event triggers) from migrations. Match the dev URL scope to the project's target database URL. For PostGIS or pgvector schemas, use `docker://postgis/latest/dev` or `docker://pgvector/pg17/dev`.
If the schema depends on extensions or external objects, use a `docker` block with a `baseline`:
```hcl
docker "postgres" "dev" {
image = "postgres:15"
schema = "public"
baseline = <<SQL
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
SQL
}
env "local" {
src = "file://schema.hcl"
dev = docker.postgres.dev.url
}
```
## Workflows
### 1. Schema Inspection
Start with a high-level overview before diving into details. The default output is HCL.
Use `--format "{{ json . }}"` for JSON or `--format "{{ sql . }}"` for SQL.
```bash
# List tables (overview first, JSON output)
atlas schema inspect --env <name> --format "{{ json . }}" | jq ".schemas[].tables[].name"
# Full SQL schema
atlas schema inspect --env <name> --format "{{ sql . }}"
# Filter with --include/--exclude (useful for large schemas)
atlas schema inspect --env <name> --include "users_*" # Only matching tables
atlas schema inspect --env <name> --exclude "*_backup" # Skip matching tables
atlas schema inspect --env <name> --exclude "*[type=trigger]" # Skip triggers
# Open visual ERD in browser (requires atlas login)
atlas schema inspect --env <name> -w
```
### 2. Schema Comparison (Diff)
Compare any two schema states:
```bash
# Compare current state to desired schema
atlas schema diff --env <name>
# Compare specific sources
atlas schema diff --env <name> --from file://migrations --to file://schema.hcl
```
### 3. Migration Generation
Generate migrations from schema changes:
```bash
# Generate migration from schema diff
atlas migrate diff --env <name> "add_users_table"
# With explicit parameters
atlas migrate diff \
--dir file://migrations \
--dev-url docker://postgres/15/dev \
--to file://schema.hcl \
"add_users_table"
```
### 4. Schema Validation
Validate schema definitions before generating migrations:
```bash
# Validate schema syntax and semantics
atlas schema validate --env <name>
# Validate against dev database
atlas schema validate --dev-url docker://postgres/15/dev --url file://schema.hcl
```
If valid, exits successfully. If invalid, prints detailed error (unresolved references, syntax issues, unsupported attributes).
### 5. Migration Linting
```bash
atlas migrate lint --env <name> --latest 1 # Lint latest migration
atlas migrate lint --env ci # Lint since git branch
atlas schema lint --env <name> # Check schema policies
```
Fixing lint issues:
- Unapplied migrations: Edit file, then `atlas migrate hash --env <name>`
- Applied migrations: Create corrective migration (never edit directly)
### 6. Migration Testing
```bash
atlas migrate test --env <name> # Requires atlas login
atlas whoami # Check login status first
```
### 7. Applying Migrations
```bash
atlas migrate apply --env <name> --dry-run # Always preview first
atlas migrate apply --env <name> # Apply
atlas migrate status --env <name> # Verify
```
## Standard Workflow
1. `atlas schema inspect --env <name>` — Understand current state
2. Edit schema files
3. `atlas schema validate --env <name>` — Check syntax
4. `atlas migrate diff --env <name> "change_name"` — Generate migration
5. `atlas migrate lint --env <name> --latest 1` — Validate
6. `atlas migrate test --env <name>` — Test (requires login)
7. If issues: edit migration, then `atlas migrate hash`
8. `atlas migrate apply --env <name> --dry-run` then apply
## Schema Sources
For HCL schemas, ORM integrations (GORM, Drizzle, SQLAlchemy, Django, Ent, Sequelize, TypeORM),
composite schemas, and dev-database dialect URLs, see `references/schema-sources.md`.
## Atlas Cloud
For registry repos, registered database targets, deployment events, pre-flight checks, and
cloud vs local command guidance, see `references/cloud.md`.
## Onboarding an Existing Project
### Baseline an existing database
To start managing an existing database with versioned migrations:
```bash
# 1. Export current schema to code
atlas schema inspect -u '<database-url>' --format '{{ sql . | split | write "src" }}'
# 2. Generate a baseline migration from the exported schema
atlas migrate diff "baseline" --to "file://src" --dev-url '<dev-url>'
# 3. Mark baseline as applied on existing databases (use version from filename)
atlas migrate apply --url '<database-url>' --baseline '<version>'
```
The baseline migration captures the current state without executing it on existing databases.
On new databases, it runs in full to create the initial schema.
## Troubleshooting
```bash
# Check installation and login
atlas version
atlas whoami
# Repair migration integrity after manual edits
atlas migrate hash --env <name>
```
**Missing driver error**: Ensure `--url` or `--dev-url` is correctly specified.
## Key Rules
1. Read `atlas.hcl` first — use environment names from config
2. Never hardcode credentials — use `getenv()`
3. Run `atlas schema validate` after schema edits
4. Always lint before applying migrations
5. Always dry-run before applying
6. Run `atlas migrate hash` after editing migration files
7. Use `atlas login` to unlock views, triggers, functions, ERD, and migration testing
8. Write migration tests for data migrations
9. Never ignore lint errors — fix them or get user approval
10. Before production deploys, check Atlas Cloud state (`atlas cloud database list`, `migration list --status FAILED`) — see `references/cloud.md`
## Documentation
- [CLI Reference](https://atlasgo.io/cli-reference)
- [Versioned Migrations](https://atlasgo.io/versioned/diff)
- [Declarative Workflow](https://atlasgo.io/declarative/apply)
- [Migration Linting](https://atlasgo.io/versioned/lint)
- [Migration Testing](https://atlasgo.io/testing/migrate)
- [Onboard Existing Database](https://atlasgo.io/versioned/import)
- [ORM Integrations](https://atlasgo.io/guides/orms)
- [Dev Database](https://atlasgo.io/concepts/dev-database)
# Schema Sources Reference
## HCL Schema
```hcl
data "hcl_schema" "<name>" {
path = "schema.hcl"
}
env "<name>" {
schema {
src = data.hcl_schema.<name>.url
}
}
```
## External Schema (ORM Integration)
The `external_schema` data source imports SQL schema from an ORM or external program.
```hcl
# GORM (Go)
data "external_schema" "gorm" {
program = ["go", "run", "-mod=mod", "ariga.io/atlas-provider-gorm", "load", "--path", "./models", "--dialect", "postgres"]
}
# Drizzle (TypeScript)
data "external_schema" "drizzle" {
program = ["npx", "drizzle-kit", "export"]
}
# SQLAlchemy (Python)
data "external_schema" "sqlalchemy" {
program = ["python", "-m", "atlas_provider_sqlalchemy", "--path", "./models", "--dialect", "postgresql"]
}
# Django (Python)
data "external_schema" "django" {
program = ["python", "manage.py", "atlas-provider-django", "--dialect", "postgresql"]
}
# Ent (Go)
env "<name>" {
schema {
src = "ent://ent/schema"
}
}
# Sequelize (Node.js)
data "external_schema" "sequelize" {
program = ["npx", "@ariga/atlas-provider-sequelize", "load", "--path", "./models", "--dialect", "postgres"]
}
# TypeORM (TypeScript)
data "external_schema" "typeorm" {
program = ["npx", "@ariga/atlas-provider-typeorm", "load", "--path", "./entities", "--dialect", "postgres"]
}
```
Wire into an environment:
```hcl
env "<name>" {
schema {
src = data.external_schema.<orm>.url
}
}
```
## Composite Schema (Pro)
Combine multiple schema sources into one:
```hcl
data "composite_schema" "app" {
schema "users" {
url = data.external_schema.auth_service.url
}
schema "graph" {
url = "ent://ent/schema"
}
schema "shared" {
url = "file://schema/shared.hcl"
}
}
```
## Dev-Database Dialects
The dev URL format depends on whether your project uses **schema-scoped** or **database-scoped** migrations. Getting this wrong causes errors like `ModifySchema is not allowed` or silently drops database-level objects (extensions, event triggers) from migrations.
**Schema-scoped** (single schema — most common): include the database name and schema scope so Atlas creates objects in the correct schema. Use this when all tables live in one schema (e.g., `public`).
| Dialect | Dev URL (schema-scoped) |
|------------|------------------------------------------------------|
| MySQL | `docker://mysql/8/dev` |
| MariaDB | `docker://maria/latest/dev` |
| PostgreSQL | `docker://postgres/17/dev?search_path=public` |
| SQLite | `sqlite://dev?mode=memory` |
| SQL Server | `docker://sqlserver/2022-latest/dev?mode=schema` |
| ClickHouse | `docker://clickhouse/23.11/dev` |
**Database-scoped** (multiple schemas or database-level objects): omit the schema scope so Atlas can manage multiple schemas and detect database-level objects like extensions and event triggers.
| Dialect | Dev URL (database-scoped) |
|------------|------------------------------------------------------|
| MySQL | `docker://mysql/8` |
| MariaDB | `docker://maria/latest` |
| PostgreSQL | `docker://postgres/17/dev` |
| SQL Server | `docker://sqlserver/2022-latest/dev?mode=database` |
| ClickHouse | `docker://clickhouse/23.11` |
**PostgreSQL with extensions** — use PostGIS or pgvector images when the schema uses those extensions:
```
docker://postgis/latest/dev?search_path=public
docker://pgvector/pg17/dev?search_path=public
```
**How to choose:** Check the project's `atlas.hcl` or target database URL. If it includes `search_path=public` (Postgres) or a specific database name (MySQL), use schema-scoped. If the project manages multiple schemas, extensions, or event triggers, use database-scoped.
See https://atlasgo.io/concepts/dev-database for additional drivers and options.
# Atlas Cloud CLI
`atlas cloud` commands read and manage resources in **Atlas Cloud** (the Atlas Registry and deployment tracking). They do **not** connect to databases directly — they report what Atlas Cloud knows about repos, registered databases (targets), and deployment events.
Use them for **operational visibility** and **pre-flight checks**. Use local commands (`atlas migrate status`, `atlas migrate apply`, `atlas schema diff`) to inspect or change an actual database.
## Prerequisites
1. **Atlas CLI** — `atlas cloud` is not only available in the community version.
2. **Authentication** — run before any cloud command:
```bash
atlas whoami # verify current org
atlas login [org] # interactive login
atlas login --token "$TOKEN" # CI / non-interactive
```
`ATLAS_TOKEN` env var is also accepted by `atlas login`.
3. If `atlas whoami` fails, stop and authenticate before proceeding.
## Command Reference
```
atlas cloud
├── repo
│ ├── list
│ ├── describe
│ ├── create
│ └── lingraph
├── database
│ ├── list
│ └── describe
└── migration
├── list
└── describe
```
### `atlas cloud repo`
Manage Atlas Registry repositories (schema or migration directory artifacts).
| Command | Purpose |
|---------|---------|
| `repo list` | List all repos with per-repo database counts (synced / failed / pending) |
| `repo describe` | Details for one repo: slug, type, driver, URL, database counts |
| `repo create` | Create an empty repo in the registry (before first push); idempotent if the repo already exists |
| `repo lingraph` | Print the migration lineage graph for a repo |
**Identify a repo** (describe): exactly one of `--id`, `--slug`, or `--name`.
**Create flags** (all required):
- `--type schema` (or `s`) — declarative schema repo
- `--type migration_directory` (or `m`) — versioned migration repo
- `--name <name>` — repo name
- `--driver <driver>` — e.g. `postgres`, `mysql`, `sqlite`, `mssql`, `clickhouse`, `cockroach`
**Lineage graph**:
```bash
atlas cloud repo lingraph --slug <slug>
atlas cloud repo lingraph --slug <slug> --open-lineage # OpenLineage format
```
### `atlas cloud database`
Query **registered migration/schema targets** (databases linked to Atlas Cloud).
| Command | Purpose |
|---------|---------|
| `database list` | List all cloud-tracked databases |
| `database describe` | Details for one database |
**Output fields**: `ID`, `Name`, `RepoName`, `EnvName`, `Status`, `CurrentVersion`, `LastDeploymentTime`.
**Database status** (`Status` column):
| Status | Meaning |
|--------|---------|
| `SYNCED` | Target matches the expected repo version |
| `PENDING` | Deployment or sync is in progress / not yet complete |
| `FAILED` | Last sync or deployment failed for this target |
**Filters** (list):
- `--env-name <env>` — filter by environment name (matches `env` blocks in `atlas.hcl`)
**Identify a database** (describe): exactly one of `--id` or `--ext-id`.
### `atlas cloud migration`
Query **deployment events** (each time migrations or schema were applied to targets).
| Command | Purpose |
|---------|---------|
| `migration list` | List deployment events with filters |
| `migration describe` | Details for one event |
**Migration event status**:
| Status | Meaning |
|--------|---------|
| `PASSED` | Deployment succeeded |
| `FAILED` | Deployment failed |
| `NO_ACTION` | No changes were needed |
| `DRY_RUN` | Dry-run only, nothing applied |
**Filters** (list):
- `--status <status>` — repeatable; values: `PASSED`, `FAILED`, `NO_ACTION`, `DRY_RUN`
- `--repo <slug>` — filter by repository slug
- `--name <substring>` — filter by database name (contains match)
- `--env-name <env>` — filter by environment
**Describe**: `--id <migration-event-id>` (required).
## Common Flags
| Flag | Commands | Purpose |
|------|----------|---------|
| `--format <template>` | list, describe (except lingraph) | Go template output; use `json` helper for machine-readable — `--format '{{json .}}'` |
| `--page <n>` | list commands | Page number to fetch (default 1); see **Pagination** below |
### Pagination
List commands (`repo list`, `database list`, `migration list`) return at most **20 records per page**. Each response ends with a footer:
```
--------------------------------
Page: 1 Page Size: 20 Total: 45
```
| Footer field | Meaning |
|--------------|---------|
| `Page` | Current page (1-based); matches the `--page` flag value |
| `Page Size` | Fixed at 20 records per page (not configurable via CLI) |
| `Total` | Total records matching the current filters across all pages |
**Are there more pages?** When `Total > Page Size` (i.e. `Total > 20`). Compute the number of pages:
```
total_pages = ceil(Total / Page Size)
```
Example: `Total: 45`, `Page Size: 20` → `ceil(45 / 20) = 3` pages.
**When to fetch the next page:**
- If `Page < total_pages`, more records exist — re-run the same command with `--page <Page + 1>`.
- If `Page == total_pages`, you have all records for the current filters.
- If `Total <= Page Size`, everything fits on one page; no further requests needed.
**Example** (45 records across 3 pages):
```bash
atlas cloud database list # page 1: records 1–20
atlas cloud database list --page 2 # page 2: records 21–40
atlas cloud database list --page 3 # page 3: records 41–45
```
With `--format '{{ json . }}'`, pagination metadata is on the `PageInfo` field (`Page`, `PageSize`, `Total`). Use it in scripts to decide whether to request another page.
**Examples**:
```bash
atlas cloud database list
atlas cloud migration list --status FAILED
```
## When to Use Which Command
| User goal | Start with |
|-----------|------------|
| Is a repo healthy across all its databases? | `atlas cloud repo list` or `repo describe --slug <slug>` |
| What version is a database on in Atlas Cloud? | `atlas cloud database list --env-name <env>` or `database describe` |
| Did a recent deployment fail? | `atlas cloud migration list --status FAILED` |
| What happened in a specific deployment? | `atlas cloud migration describe --id <id>` |
| Create a registry repo before first push | `atlas cloud repo create --type m --name <n> --driver postgres` |
| Check object dependencies | `atlas cloud repo lingraph --slug <slug>` |
| Which org am I connected to? | `atlas whoami` |
| Can I push a schema change or migration to database X? | `atlas cloud database list` then `atlas cloud database describe --id <id>` using the id of database X from the list |
## Agent Workflows
### Pre-deployment readiness
Before recommending `atlas migrate apply` or a CI deploy, check Atlas Cloud state:
```
Task Progress:
- [ ] Verify auth: atlas whoami
- [ ] Check target status: atlas cloud database list --env-name <env>
- [ ] Check for failed deployments: atlas cloud migration list --status FAILED --env-name <env>
- [ ] Check repo health: atlas cloud repo describe --slug <slug>
```
**Decision rules**:
- Any database with `Status=FAILED` → investigate before applying. Run `migration list --status FAILED` filtered to that env/repo, then `migration describe` on the event ID.
- Any database with `Status=PENDING` → a deployment may be in flight; wait or confirm before starting another.
- All targets `SYNCED` and no recent `FAILED` events → cloud state looks healthy. Still run local checks (`atlas migrate status`, lint) before applying.
- `repo describe` shows `Databases Failed > 0` → at least one target in that repo is unhealthy; drill into `database list` and `migration list`.
### Investigate a failed deployment
1. `atlas cloud migration list --status FAILED --repo <slug>` (add `--env-name` or `--name` to narrow)
2. `atlas cloud migration describe --id <id>` for version, completion time, and multi-target results
3. `atlas cloud database describe --id <id>` on affected targets to see current version vs expected
4. Use local `atlas migrate status --env <env>` to compare the live database revision table against cloud state
### Audit environments
Read `atlas.hcl` first to find environment names (`env` block names). For each environment you want to compare, run:
```bash
atlas cloud database list --env-name <env>
atlas cloud migration list --env-name <env>
```
Repeat for every relevant `env` in the project (e.g. dev, staging, prod — names vary). Compare `CurrentVersion` across environments to spot version skew.
### Set up a new registry repo
1. `atlas cloud repo create --type migration_directory --name <name> --driver postgres`
2. Note the returned `Slug` and `URL`
3. Reference in `atlas.hcl`: `migration { dir = "atlas://<slug>" }`
4. Push migrations with `atlas migrate push` (separate from `atlas cloud`)
## Cloud vs Local Commands
| Concern | Atlas Cloud (`atlas cloud …`) | Local (`atlas migrate/schema …`) |
|---------|-------------------------------|-----------------------------------|
| Registry repos & artifacts | ✅ | `migrate push`, `schema push` |
| Registered target status | ✅ | — |
| Deployment event history | ✅ | — |
| Live database revision table | — | `migrate status` |
| Schema drift vs desired state | — | `schema diff`, `migrate lint` |
| Apply changes to a database | — | `migrate apply`, `schema apply` |
Cloud commands answer **"what does Atlas Cloud know?"** Local commands answer **"what is actually in the database?"** Use both when validating readiness.
## Reporting Results to the User
When summarizing cloud command output:
1. State the org (`atlas whoami`) and filters used
2. Highlight `FAILED` / `PENDING` statuses prominently
3. For migrations, include `Version`, `Status`, `CompletedAt`, and `TargetsSucceeded/TargetsTotal` when present
4. Distinguish cloud-reported state from local database state — recommend local verification when the user plans to apply changes
5. For list commands, read the pagination footer (or `PageInfo` in JSON). If `Total > Page Size`, compute `total_pages = ceil(Total / Page Size)` and fetch remaining pages with `--page 2`, `--page 3`, etc. until `Page == total_pages` before concluding the result set is complete
## Error Handling
| Error | Action |
|-------|--------|
| `'atlas login' is required` | Run `atlas login` or set token |
| `repository not found` / `database not found` / `migration not found` | Verify identifier; try `list` first to get correct ID/slug |
| `invalid --status value` | Use `PASSED`, `FAILED`, `NO_ACTION`, or `DRY_RUN` |
| `invalid --type` | Use `schema`/`s` or `migration_directory`/`m` |
| Mutually exclusive flags (`--id` vs `--slug`) | Provide exactly one identifier |
Claude will automatically load the skill when database operations are requested.
Cursor supports skills in the nightly release channel. Add the skill to your project:
mkdir -p .cursor/skills/atlas/references
---
name: atlas
description: "Database schema management and migrations with Atlas CLI. Use when: generating migrations, diffing schemas, linting or testing migrations, applying schema changes, inspecting databases, working with atlas.hcl, schema.hcl, or ORM schemas (GORM, Drizzle, SQLAlchemy, Django, Ent, Sequelize, TypeORM), validating schema definitions, or checking Atlas Cloud registry and deployment status."
---
# Atlas Schema Migrations
## Security
Never hardcode credentials. Use environment variables:
```hcl
env "prod" {
url = getenv("DATABASE_URL")
}
```
## Quick Reference
Use `--help` on any command for comprehensive docs and examples:
```bash
atlas migrate diff --help
```
Always use `--env` to reference configurations from `atlas.hcl` — this avoids passing
database credentials to the LLM context.
```bash
# Common
atlas schema inspect --env <name> # Inspect schema
atlas schema validate --env <name> # Validate schema syntax/semantics
atlas schema diff --env <name> # Compare schemas
atlas schema lint --env <name> # Check schema policies
atlas schema test --env <name> # Test schema
# Declarative workflow
atlas schema plan --env <name> # Plan schema changes
atlas schema apply --env <name> --dry-run # Preview changes
atlas schema apply --env <name> # Apply schema changes
# Versioned workflow
atlas migrate diff --env <name> "migration_name" # Generate migration
atlas migrate lint --env <name> --latest 1 # Validate migration
atlas migrate test --env <name> # Test migration
atlas migrate apply --env <name> --dry-run # Preview changes
atlas migrate apply --env <name> # Apply migration
atlas migrate status --env <name> # Check status
```
## Choosing a Workflow
```
Schema change needed
├─ Project has migrations/ dir or migration config in atlas.hcl?
│ ├─ Yes → Versioned: migrate diff → lint → test → apply
│ └─ No → Declarative: schema apply --dry-run → apply
├─ Iterating on local database?
│ └─ Use schema apply --auto-approve for fast edit-apply cycles
└─ Not sure → Read atlas.hcl first
```
**Tip:** `atlas schema apply` applies schema changes directly to a local database without generating migration files. This is useful for fast iteration during development — edit the schema, run `schema apply`, and see the result immediately.
## Example
```
User: Add an email column to the users table
Agent steps:
1. atlas schema inspect --env dev # understand current state
2. Edit schema source file # add email column
3. atlas schema validate --env dev # verify syntax
4. atlas migrate diff --env dev "add_email" # generate migration
5. atlas migrate lint --env dev --latest 1 # check for issues
6. atlas migrate apply --env dev --dry-run # preview before applying
```
## Core Concepts
### Configuration File (atlas.hcl)
Always read the project's `atlas.hcl` first — it contains environment configurations:
```hcl
env "<name>" {
url = getenv("DATABASE_URL")
dev = "docker://postgres/15/dev?search_path=public"
migration {
dir = "file://migrations"
}
schema {
src = "file://schema.hcl"
}
}
```
### Dev Database
Atlas uses a temporary "dev-database" to process and validate schemas. The URL format depends on whether you work with a **single schema** or **multiple schemas**:
```bash
# Schema-scoped (single schema — most common)
--dev-url "docker://mysql/8/dev"
--dev-url "docker://postgres/15/dev?search_path=public"
--dev-url "sqlite://dev?mode=memory"
--dev-url "docker://sqlserver/2022-latest/dev?mode=schema"
# Database-scoped (multiple schemas, extensions, or event triggers)
--dev-url "docker://mysql/8"
--dev-url "docker://postgres/15/dev"
--dev-url "docker://sqlserver/2022-latest/dev?mode=database"
```
**Important:** Using the wrong scope causes errors (`ModifySchema is not allowed`) or silently drops database-level objects (extensions, event triggers) from migrations. Match the dev URL scope to the project's target database URL. For PostGIS or pgvector schemas, use `docker://postgis/latest/dev` or `docker://pgvector/pg17/dev`.
If the schema depends on extensions or external objects, use a `docker` block with a `baseline`:
```hcl
docker "postgres" "dev" {
image = "postgres:15"
schema = "public"
baseline = <<SQL
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
SQL
}
env "local" {
src = "file://schema.hcl"
dev = docker.postgres.dev.url
}
```
## Workflows
### 1. Schema Inspection
Start with a high-level overview before diving into details. The default output is HCL.
Use `--format "{{ json . }}"` for JSON or `--format "{{ sql . }}"` for SQL.
```bash
# List tables (overview first, JSON output)
atlas schema inspect --env <name> --format "{{ json . }}" | jq ".schemas[].tables[].name"
# Full SQL schema
atlas schema inspect --env <name> --format "{{ sql . }}"
# Filter with --include/--exclude (useful for large schemas)
atlas schema inspect --env <name> --include "users_*" # Only matching tables
atlas schema inspect --env <name> --exclude "*_backup" # Skip matching tables
atlas schema inspect --env <name> --exclude "*[type=trigger]" # Skip triggers
# Open visual ERD in browser (requires atlas login)
atlas schema inspect --env <name> -w
```
### 2. Schema Comparison (Diff)
Compare any two schema states:
```bash
# Compare current state to desired schema
atlas schema diff --env <name>
# Compare specific sources
atlas schema diff --env <name> --from file://migrations --to file://schema.hcl
```
### 3. Migration Generation
Generate migrations from schema changes:
```bash
# Generate migration from schema diff
atlas migrate diff --env <name> "add_users_table"
# With explicit parameters
atlas migrate diff \
--dir file://migrations \
--dev-url docker://postgres/15/dev \
--to file://schema.hcl \
"add_users_table"
```
### 4. Schema Validation
Validate schema definitions before generating migrations:
```bash
# Validate schema syntax and semantics
atlas schema validate --env <name>
# Validate against dev database
atlas schema validate --dev-url docker://postgres/15/dev --url file://schema.hcl
```
If valid, exits successfully. If invalid, prints detailed error (unresolved references, syntax issues, unsupported attributes).
### 5. Migration Linting
```bash
atlas migrate lint --env <name> --latest 1 # Lint latest migration
atlas migrate lint --env ci # Lint since git branch
atlas schema lint --env <name> # Check schema policies
```
Fixing lint issues:
- Unapplied migrations: Edit file, then `atlas migrate hash --env <name>`
- Applied migrations: Create corrective migration (never edit directly)
### 6. Migration Testing
```bash
atlas migrate test --env <name> # Requires atlas login
atlas whoami # Check login status first
```
### 7. Applying Migrations
```bash
atlas migrate apply --env <name> --dry-run # Always preview first
atlas migrate apply --env <name> # Apply
atlas migrate status --env <name> # Verify
```
## Standard Workflow
1. `atlas schema inspect --env <name>` — Understand current state
2. Edit schema files
3. `atlas schema validate --env <name>` — Check syntax
4. `atlas migrate diff --env <name> "change_name"` — Generate migration
5. `atlas migrate lint --env <name> --latest 1` — Validate
6. `atlas migrate test --env <name>` — Test (requires login)
7. If issues: edit migration, then `atlas migrate hash`
8. `atlas migrate apply --env <name> --dry-run` then apply
## Schema Sources
For HCL schemas, ORM integrations (GORM, Drizzle, SQLAlchemy, Django, Ent, Sequelize, TypeORM),
composite schemas, and dev-database dialect URLs, see `references/schema-sources.md`.
## Atlas Cloud
For registry repos, registered database targets, deployment events, pre-flight checks, and
cloud vs local command guidance, see `references/cloud.md`.
## Onboarding an Existing Project
### Baseline an existing database
To start managing an existing database with versioned migrations:
```bash
# 1. Export current schema to code
atlas schema inspect -u '<database-url>' --format '{{ sql . | split | write "src" }}'
# 2. Generate a baseline migration from the exported schema
atlas migrate diff "baseline" --to "file://src" --dev-url '<dev-url>'
# 3. Mark baseline as applied on existing databases (use version from filename)
atlas migrate apply --url '<database-url>' --baseline '<version>'
```
The baseline migration captures the current state without executing it on existing databases.
On new databases, it runs in full to create the initial schema.
## Troubleshooting
```bash
# Check installation and login
atlas version
atlas whoami
# Repair migration integrity after manual edits
atlas migrate hash --env <name>
```
**Missing driver error**: Ensure `--url` or `--dev-url` is correctly specified.
## Key Rules
1. Read `atlas.hcl` first — use environment names from config
2. Never hardcode credentials — use `getenv()`
3. Run `atlas schema validate` after schema edits
4. Always lint before applying migrations
5. Always dry-run before applying
6. Run `atlas migrate hash` after editing migration files
7. Use `atlas login` to unlock views, triggers, functions, ERD, and migration testing
8. Write migration tests for data migrations
9. Never ignore lint errors — fix them or get user approval
10. Before production deploys, check Atlas Cloud state (`atlas cloud database list`, `migration list --status FAILED`) — see `references/cloud.md`
## Documentation
- [CLI Reference](https://atlasgo.io/cli-reference)
- [Versioned Migrations](https://atlasgo.io/versioned/diff)
- [Declarative Workflow](https://atlasgo.io/declarative/apply)
- [Migration Linting](https://atlasgo.io/versioned/lint)
- [Migration Testing](https://atlasgo.io/testing/migrate)
- [Onboard Existing Database](https://atlasgo.io/versioned/import)
- [ORM Integrations](https://atlasgo.io/guides/orms)
- [Dev Database](https://atlasgo.io/concepts/dev-database)
# Schema Sources Reference
## HCL Schema
```hcl
data "hcl_schema" "<name>" {
path = "schema.hcl"
}
env "<name>" {
schema {
src = data.hcl_schema.<name>.url
}
}
```
## External Schema (ORM Integration)
The `external_schema` data source imports SQL schema from an ORM or external program.
```hcl
# GORM (Go)
data "external_schema" "gorm" {
program = ["go", "run", "-mod=mod", "ariga.io/atlas-provider-gorm", "load", "--path", "./models", "--dialect", "postgres"]
}
# Drizzle (TypeScript)
data "external_schema" "drizzle" {
program = ["npx", "drizzle-kit", "export"]
}
# SQLAlchemy (Python)
data "external_schema" "sqlalchemy" {
program = ["python", "-m", "atlas_provider_sqlalchemy", "--path", "./models", "--dialect", "postgresql"]
}
# Django (Python)
data "external_schema" "django" {
program = ["python", "manage.py", "atlas-provider-django", "--dialect", "postgresql"]
}
# Ent (Go)
env "<name>" {
schema {
src = "ent://ent/schema"
}
}
# Sequelize (Node.js)
data "external_schema" "sequelize" {
program = ["npx", "@ariga/atlas-provider-sequelize", "load", "--path", "./models", "--dialect", "postgres"]
}
# TypeORM (TypeScript)
data "external_schema" "typeorm" {
program = ["npx", "@ariga/atlas-provider-typeorm", "load", "--path", "./entities", "--dialect", "postgres"]
}
```
Wire into an environment:
```hcl
env "<name>" {
schema {
src = data.external_schema.<orm>.url
}
}
```
## Composite Schema (Pro)
Combine multiple schema sources into one:
```hcl
data "composite_schema" "app" {
schema "users" {
url = data.external_schema.auth_service.url
}
schema "graph" {
url = "ent://ent/schema"
}
schema "shared" {
url = "file://schema/shared.hcl"
}
}
```
## Dev-Database Dialects
The dev URL format depends on whether your project uses **schema-scoped** or **database-scoped** migrations. Getting this wrong causes errors like `ModifySchema is not allowed` or silently drops database-level objects (extensions, event triggers) from migrations.
**Schema-scoped** (single schema — most common): include the database name and schema scope so Atlas creates objects in the correct schema. Use this when all tables live in one schema (e.g., `public`).
| Dialect | Dev URL (schema-scoped) |
|------------|------------------------------------------------------|
| MySQL | `docker://mysql/8/dev` |
| MariaDB | `docker://maria/latest/dev` |
| PostgreSQL | `docker://postgres/17/dev?search_path=public` |
| SQLite | `sqlite://dev?mode=memory` |
| SQL Server | `docker://sqlserver/2022-latest/dev?mode=schema` |
| ClickHouse | `docker://clickhouse/23.11/dev` |
**Database-scoped** (multiple schemas or database-level objects): omit the schema scope so Atlas can manage multiple schemas and detect database-level objects like extensions and event triggers.
| Dialect | Dev URL (database-scoped) |
|------------|------------------------------------------------------|
| MySQL | `docker://mysql/8` |
| MariaDB | `docker://maria/latest` |
| PostgreSQL | `docker://postgres/17/dev` |
| SQL Server | `docker://sqlserver/2022-latest/dev?mode=database` |
| ClickHouse | `docker://clickhouse/23.11` |
**PostgreSQL with extensions** — use PostGIS or pgvector images when the schema uses those extensions:
```
docker://postgis/latest/dev?search_path=public
docker://pgvector/pg17/dev?search_path=public
```
**How to choose:** Check the project's `atlas.hcl` or target database URL. If it includes `search_path=public` (Postgres) or a specific database name (MySQL), use schema-scoped. If the project manages multiple schemas, extensions, or event triggers, use database-scoped.
See https://atlasgo.io/concepts/dev-database for additional drivers and options.
# Atlas Cloud CLI
`atlas cloud` commands read and manage resources in **Atlas Cloud** (the Atlas Registry and deployment tracking). They do **not** connect to databases directly — they report what Atlas Cloud knows about repos, registered databases (targets), and deployment events.
Use them for **operational visibility** and **pre-flight checks**. Use local commands (`atlas migrate status`, `atlas migrate apply`, `atlas schema diff`) to inspect or change an actual database.
## Prerequisites
1. **Atlas CLI** — `atlas cloud` is not only available in the community version.
2. **Authentication** — run before any cloud command:
```bash
atlas whoami # verify current org
atlas login [org] # interactive login
atlas login --token "$TOKEN" # CI / non-interactive
```
`ATLAS_TOKEN` env var is also accepted by `atlas login`.
3. If `atlas whoami` fails, stop and authenticate before proceeding.
## Command Reference
```
atlas cloud
├── repo
│ ├── list
│ ├── describe
│ ├── create
│ └── lingraph
├── database
│ ├── list
│ └── describe
└── migration
├── list
└── describe
```
### `atlas cloud repo`
Manage Atlas Registry repositories (schema or migration directory artifacts).
| Command | Purpose |
|---------|---------|
| `repo list` | List all repos with per-repo database counts (synced / failed / pending) |
| `repo describe` | Details for one repo: slug, type, driver, URL, database counts |
| `repo create` | Create an empty repo in the registry (before first push); idempotent if the repo already exists |
| `repo lingraph` | Print the migration lineage graph for a repo |
**Identify a repo** (describe): exactly one of `--id`, `--slug`, or `--name`.
**Create flags** (all required):
- `--type schema` (or `s`) — declarative schema repo
- `--type migration_directory` (or `m`) — versioned migration repo
- `--name <name>` — repo name
- `--driver <driver>` — e.g. `postgres`, `mysql`, `sqlite`, `mssql`, `clickhouse`, `cockroach`
**Lineage graph**:
```bash
atlas cloud repo lingraph --slug <slug>
atlas cloud repo lingraph --slug <slug> --open-lineage # OpenLineage format
```
### `atlas cloud database`
Query **registered migration/schema targets** (databases linked to Atlas Cloud).
| Command | Purpose |
|---------|---------|
| `database list` | List all cloud-tracked databases |
| `database describe` | Details for one database |
**Output fields**: `ID`, `Name`, `RepoName`, `EnvName`, `Status`, `CurrentVersion`, `LastDeploymentTime`.
**Database status** (`Status` column):
| Status | Meaning |
|--------|---------|
| `SYNCED` | Target matches the expected repo version |
| `PENDING` | Deployment or sync is in progress / not yet complete |
| `FAILED` | Last sync or deployment failed for this target |
**Filters** (list):
- `--env-name <env>` — filter by environment name (matches `env` blocks in `atlas.hcl`)
**Identify a database** (describe): exactly one of `--id` or `--ext-id`.
### `atlas cloud migration`
Query **deployment events** (each time migrations or schema were applied to targets).
| Command | Purpose |
|---------|---------|
| `migration list` | List deployment events with filters |
| `migration describe` | Details for one event |
**Migration event status**:
| Status | Meaning |
|--------|---------|
| `PASSED` | Deployment succeeded |
| `FAILED` | Deployment failed |
| `NO_ACTION` | No changes were needed |
| `DRY_RUN` | Dry-run only, nothing applied |
**Filters** (list):
- `--status <status>` — repeatable; values: `PASSED`, `FAILED`, `NO_ACTION`, `DRY_RUN`
- `--repo <slug>` — filter by repository slug
- `--name <substring>` — filter by database name (contains match)
- `--env-name <env>` — filter by environment
**Describe**: `--id <migration-event-id>` (required).
## Common Flags
| Flag | Commands | Purpose |
|------|----------|---------|
| `--format <template>` | list, describe (except lingraph) | Go template output; use `json` helper for machine-readable — `--format '{{json .}}'` |
| `--page <n>` | list commands | Page number to fetch (default 1); see **Pagination** below |
### Pagination
List commands (`repo list`, `database list`, `migration list`) return at most **20 records per page**. Each response ends with a footer:
```
--------------------------------
Page: 1 Page Size: 20 Total: 45
```
| Footer field | Meaning |
|--------------|---------|
| `Page` | Current page (1-based); matches the `--page` flag value |
| `Page Size` | Fixed at 20 records per page (not configurable via CLI) |
| `Total` | Total records matching the current filters across all pages |
**Are there more pages?** When `Total > Page Size` (i.e. `Total > 20`). Compute the number of pages:
```
total_pages = ceil(Total / Page Size)
```
Example: `Total: 45`, `Page Size: 20` → `ceil(45 / 20) = 3` pages.
**When to fetch the next page:**
- If `Page < total_pages`, more records exist — re-run the same command with `--page <Page + 1>`.
- If `Page == total_pages`, you have all records for the current filters.
- If `Total <= Page Size`, everything fits on one page; no further requests needed.
**Example** (45 records across 3 pages):
```bash
atlas cloud database list # page 1: records 1–20
atlas cloud database list --page 2 # page 2: records 21–40
atlas cloud database list --page 3 # page 3: records 41–45
```
With `--format '{{ json . }}'`, pagination metadata is on the `PageInfo` field (`Page`, `PageSize`, `Total`). Use it in scripts to decide whether to request another page.
**Examples**:
```bash
atlas cloud database list
atlas cloud migration list --status FAILED
```
## When to Use Which Command
| User goal | Start with |
|-----------|------------|
| Is a repo healthy across all its databases? | `atlas cloud repo list` or `repo describe --slug <slug>` |
| What version is a database on in Atlas Cloud? | `atlas cloud database list --env-name <env>` or `database describe` |
| Did a recent deployment fail? | `atlas cloud migration list --status FAILED` |
| What happened in a specific deployment? | `atlas cloud migration describe --id <id>` |
| Create a registry repo before first push | `atlas cloud repo create --type m --name <n> --driver postgres` |
| Check object dependencies | `atlas cloud repo lingraph --slug <slug>` |
| Which org am I connected to? | `atlas whoami` |
| Can I push a schema change or migration to database X? | `atlas cloud database list` then `atlas cloud database describe --id <id>` using the id of database X from the list |
## Agent Workflows
### Pre-deployment readiness
Before recommending `atlas migrate apply` or a CI deploy, check Atlas Cloud state:
```
Task Progress:
- [ ] Verify auth: atlas whoami
- [ ] Check target status: atlas cloud database list --env-name <env>
- [ ] Check for failed deployments: atlas cloud migration list --status FAILED --env-name <env>
- [ ] Check repo health: atlas cloud repo describe --slug <slug>
```
**Decision rules**:
- Any database with `Status=FAILED` → investigate before applying. Run `migration list --status FAILED` filtered to that env/repo, then `migration describe` on the event ID.
- Any database with `Status=PENDING` → a deployment may be in flight; wait or confirm before starting another.
- All targets `SYNCED` and no recent `FAILED` events → cloud state looks healthy. Still run local checks (`atlas migrate status`, lint) before applying.
- `repo describe` shows `Databases Failed > 0` → at least one target in that repo is unhealthy; drill into `database list` and `migration list`.
### Investigate a failed deployment
1. `atlas cloud migration list --status FAILED --repo <slug>` (add `--env-name` or `--name` to narrow)
2. `atlas cloud migration describe --id <id>` for version, completion time, and multi-target results
3. `atlas cloud database describe --id <id>` on affected targets to see current version vs expected
4. Use local `atlas migrate status --env <env>` to compare the live database revision table against cloud state
### Audit environments
Read `atlas.hcl` first to find environment names (`env` block names). For each environment you want to compare, run:
```bash
atlas cloud database list --env-name <env>
atlas cloud migration list --env-name <env>
```
Repeat for every relevant `env` in the project (e.g. dev, staging, prod — names vary). Compare `CurrentVersion` across environments to spot version skew.
### Set up a new registry repo
1. `atlas cloud repo create --type migration_directory --name <name> --driver postgres`
2. Note the returned `Slug` and `URL`
3. Reference in `atlas.hcl`: `migration { dir = "atlas://<slug>" }`
4. Push migrations with `atlas migrate push` (separate from `atlas cloud`)
## Cloud vs Local Commands
| Concern | Atlas Cloud (`atlas cloud …`) | Local (`atlas migrate/schema …`) |
|---------|-------------------------------|-----------------------------------|
| Registry repos & artifacts | ✅ | `migrate push`, `schema push` |
| Registered target status | ✅ | — |
| Deployment event history | ✅ | — |
| Live database revision table | — | `migrate status` |
| Schema drift vs desired state | — | `schema diff`, `migrate lint` |
| Apply changes to a database | — | `migrate apply`, `schema apply` |
Cloud commands answer **"what does Atlas Cloud know?"** Local commands answer **"what is actually in the database?"** Use both when validating readiness.
## Reporting Results to the User
When summarizing cloud command output:
1. State the org (`atlas whoami`) and filters used
2. Highlight `FAILED` / `PENDING` statuses prominently
3. For migrations, include `Version`, `Status`, `CompletedAt`, and `TargetsSucceeded/TargetsTotal` when present
4. Distinguish cloud-reported state from local database state — recommend local verification when the user plans to apply changes
5. For list commands, read the pagination footer (or `PageInfo` in JSON). If `Total > Page Size`, compute `total_pages = ceil(Total / Page Size)` and fetch remaining pages with `--page 2`, `--page 3`, etc. until `Page == total_pages` before concluding the result set is complete
## Error Handling
| Error | Action |
|-------|--------|
| `'atlas login' is required` | Run `atlas login` or set token |
| `repository not found` / `database not found` / `migration not found` | Verify identifier; try `list` first to get correct ID/slug |
| `invalid --status value` | Use `PASSED`, `FAILED`, `NO_ACTION`, or `DRY_RUN` |
| `invalid --type` | Use `schema`/`s` or `migration_directory`/`m` |
| Mutually exclusive flags (`--id` vs `--slug`) | Provide exactly one identifier |
Enable Agent Skills in Cursor Settings → Rules → Import Settings.
Add the skill to your project for team-wide consistency:
mkdir -p .cursor/skills/atlas/references # Cursor
mkdir -p .claude/skills/atlas/references # Claude
mkdir -p .codex/skills/atlas/references # Codex
---
name: atlas
description: "Database schema management and migrations with Atlas CLI. Use when: generating migrations, diffing schemas, linting or testing migrations, applying schema changes, inspecting databases, working with atlas.hcl, schema.hcl, or ORM schemas (GORM, Drizzle, SQLAlchemy, Django, Ent, Sequelize, TypeORM), validating schema definitions, or checking Atlas Cloud registry and deployment status."
---
# Atlas Schema Migrations
## Security
Never hardcode credentials. Use environment variables:
```hcl
env "prod" {
url = getenv("DATABASE_URL")
}
```
## Quick Reference
Use `--help` on any command for comprehensive docs and examples:
```bash
atlas migrate diff --help
```
Always use `--env` to reference configurations from `atlas.hcl` — this avoids passing
database credentials to the LLM context.
```bash
# Common
atlas schema inspect --env <name> # Inspect schema
atlas schema validate --env <name> # Validate schema syntax/semantics
atlas schema diff --env <name> # Compare schemas
atlas schema lint --env <name> # Check schema policies
atlas schema test --env <name> # Test schema
# Declarative workflow
atlas schema plan --env <name> # Plan schema changes
atlas schema apply --env <name> --dry-run # Preview changes
atlas schema apply --env <name> # Apply schema changes
# Versioned workflow
atlas migrate diff --env <name> "migration_name" # Generate migration
atlas migrate lint --env <name> --latest 1 # Validate migration
atlas migrate test --env <name> # Test migration
atlas migrate apply --env <name> --dry-run # Preview changes
atlas migrate apply --env <name> # Apply migration
atlas migrate status --env <name> # Check status
```
## Choosing a Workflow
```
Schema change needed
├─ Project has migrations/ dir or migration config in atlas.hcl?
│ ├─ Yes → Versioned: migrate diff → lint → test → apply
│ └─ No → Declarative: schema apply --dry-run → apply
├─ Iterating on local database?
│ └ ─ Use schema apply --auto-approve for fast edit-apply cycles
└─ Not sure → Read atlas.hcl first
```
**Tip:** `atlas schema apply` applies schema changes directly to a local database without generating migration files. This is useful for fast iteration during development — edit the schema, run `schema apply`, and see the result immediately.
## Example
```
User: Add an email column to the users table
Agent steps:
1. atlas schema inspect --env dev # understand current state
2. Edit schema source file # add email column
3. atlas schema validate --env dev # verify syntax
4. atlas migrate diff --env dev "add_email" # generate migration
5. atlas migrate lint --env dev --latest 1 # check for issues
6. atlas migrate apply --env dev --dry-run # preview before applying
```
## Core Concepts
### Configuration File (atlas.hcl)
Always read the project's `atlas.hcl` first — it contains environment configurations:
```hcl
env "<name>" {
url = getenv("DATABASE_URL")
dev = "docker://postgres/15/dev?search_path=public"
migration {
dir = "file://migrations"
}
schema {
src = "file://schema.hcl"
}
}
```
### Dev Database
Atlas uses a temporary "dev-database" to process and validate schemas. The URL format depends on whether you work with a **single schema** or **multiple schemas**:
```bash
# Schema-scoped (single schema — most common)
--dev-url "docker://mysql/8/dev"
--dev-url "docker://postgres/15/dev?search_path=public"
--dev-url "sqlite://dev?mode=memory"
--dev-url "docker://sqlserver/2022-latest/dev?mode=schema"
# Database-scoped (multiple schemas, extensions, or event triggers)
--dev-url "docker://mysql/8"
--dev-url "docker://postgres/15/dev"
--dev-url "docker://sqlserver/2022-latest/dev?mode=database"
```
**Important:** Using the wrong scope causes errors (`ModifySchema is not allowed`) or silently drops database-level objects (extensions, event triggers) from migrations. Match the dev URL scope to the project's target database URL. For PostGIS or pgvector schemas, use `docker://postgis/latest/dev` or `docker://pgvector/pg17/dev`.
If the schema depends on extensions or external objects, use a `docker` block with a `baseline`:
```hcl
docker "postgres" "dev" {
image = "postgres:15"
schema = "public"
baseline = <<SQL
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
SQL
}
env "local" {
src = "file://schema.hcl"
dev = docker.postgres.dev.url
}
```
## Workflows
### 1. Schema Inspection
Start with a high-level overview before diving into details. The default output is HCL.
Use `--format "{{ json . }}"` for JSON or `--format "{{ sql . }}"` for SQL.
```bash
# List tables (overview first, JSON output)
atlas schema inspect --env <name> --format "{{ json . }}" | jq ".schemas[].tables[].name"
# Full SQL schema
atlas schema inspect --env <name> --format "{{ sql . }}"
# Filter with --include/--exclude (useful for large schemas)
atlas schema inspect --env <name> --include "users_*" # Only matching tables
atlas schema inspect --env <name> --exclude "*_backup" # Skip matching tables
atlas schema inspect --env <name> --exclude "*[type=trigger]" # Skip triggers
# Open visual ERD in browser (requires atlas login)
atlas schema inspect --env <name> -w
```
### 2. Schema Comparison (Diff)
Compare any two schema states:
```bash
# Compare current state to desired schema
atlas schema diff --env <name>
# Compare specific sources
atlas schema diff --env <name> --from file://migrations --to file://schema.hcl
```
### 3. Migration Generation
Generate migrations from schema changes:
```bash
# Generate migration from schema diff
atlas migrate diff --env <name> "add_users_table"
# With explicit parameters
atlas migrate diff \
--dir file://migrations \
--dev-url docker://postgres/15/dev \
--to file://schema.hcl \
"add_users_table"
```
### 4. Schema Validation
Validate schema definitions before generating migrations:
```bash
# Validate schema syntax and semantics
atlas schema validate --env <name>
# Validate against dev database
atlas schema validate --dev-url docker://postgres/15/dev --url file://schema.hcl
```
If valid, exits successfully. If invalid, prints detailed error (unresolved references, syntax issues, unsupported attributes).
### 5. Migration Linting
```bash
atlas migrate lint --env <name> --latest 1 # Lint latest migration
atlas migrate lint --env ci # Lint since git branch
atlas schema lint --env <name> # Check schema policies
```
Fixing lint issues:
- Unapplied migrations: Edit file, then `atlas migrate hash --env <name>`
- Applied migrations: Create corrective migration (never edit directly)
### 6. Migration Testing
```bash
atlas migrate test --env <name> # Requires atlas login
atlas whoami # Check login status first
```
### 7. Applying Migrations
```bash
atlas migrate apply --env <name> --dry-run # Always preview first
atlas migrate apply --env <name> # Apply
atlas migrate status --env <name> # Verify
```
## Standard Workflow
1. `atlas schema inspect --env <name>` — Understand current state
2. Edit schema files
3. `atlas schema validate --env <name>` — Check syntax
4. `atlas migrate diff --env <name> "change_name"` — Generate migration
5. `atlas migrate lint --env <name> --latest 1` — Validate
6. `atlas migrate test --env <name>` — Test (requires login)
7. If issues: edit migration, then `atlas migrate hash`
8. `atlas migrate apply --env <name> --dry-run` then apply
## Schema Sources
For HCL schemas, ORM integrations (GORM, Drizzle, SQLAlchemy, Django, Ent, Sequelize, TypeORM),
composite schemas, and dev-database dialect URLs, see `references/schema-sources.md`.
## Atlas Cloud
For registry repos, registered database targets, deployment events, pre-flight checks, and
cloud vs local command guidance, see `references/cloud.md`.
## Onboarding an Existing Project
### Baseline an existing database
To start managing an existing database with versioned migrations:
```bash
# 1. Export current schema to code
atlas schema inspect -u '<database-url>' --format '{{ sql . | split | write "src" }}'
# 2. Generate a baseline migration from the exported schema
atlas migrate diff "baseline" --to "file://src" --dev-url '<dev-url>'
# 3. Mark baseline as applied on existing databases (use version from filename)
atlas migrate apply --url '<database-url>' --baseline '<version>'
```
The baseline migration captures the current state without executing it on existing databases.
On new databases, it runs in full to create the initial schema.
## Troubleshooting
```bash
# Check installation and login
atlas version
atlas whoami
# Repair migration integrity after manual edits
atlas migrate hash --env <name>
```
**Missing driver error**: Ensure `--url` or `--dev-url` is correctly specified.
## Key Rules
1. Read `atlas.hcl` first — use environment names from config
2. Never hardcode credentials — use `getenv()`
3. Run `atlas schema validate` after schema edits
4. Always lint before applying migrations
5. Always dry-run before applying
6. Run `atlas migrate hash` after editing migration files
7. Use `atlas login` to unlock views, triggers, functions, ERD, and migration testing
8. Write migration tests for data migrations
9. Never ignore lint errors — fix them or get user approval
10. Before production deploys, check Atlas Cloud state (`atlas cloud database list`, `migration list --status FAILED`) — see `references/cloud.md`
## Documentation
- [CLI Reference](https://atlasgo.io/cli-reference)
- [Versioned Migrations](https://atlasgo.io/versioned/diff)
- [Declarative Workflow](https://atlasgo.io/declarative/apply)
- [Migration Linting](https://atlasgo.io/versioned/lint)
- [Migration Testing](https://atlasgo.io/testing/migrate)
- [Onboard Existing Database](https://atlasgo.io/versioned/import)
- [ORM Integrations](https://atlasgo.io/guides/orms)
- [Dev Database](https://atlasgo.io/concepts/dev-database)
# Schema Sources Reference
## HCL Schema
```hcl
data "hcl_schema" "<name>" {
path = "schema.hcl"
}
env "<name>" {
schema {
src = data.hcl_schema.<name>.url
}
}
```
## External Schema (ORM Integration)
The `external_schema` data source imports SQL schema from an ORM or external program.
```hcl
# GORM (Go)
data "external_schema" "gorm" {
program = ["go", "run", "-mod=mod", "ariga.io/atlas-provider-gorm", "load", "--path", "./models", "--dialect", "postgres"]
}
# Drizzle (TypeScript)
data "external_schema" "drizzle" {
program = ["npx", "drizzle-kit", "export"]
}
# SQLAlchemy (Python)
data "external_schema" "sqlalchemy" {
program = ["python", "-m", "atlas_provider_sqlalchemy", "--path", "./models", "--dialect", "postgresql"]
}
# Django (Python)
data "external_schema" "django" {
program = ["python", "manage.py", "atlas-provider-django", "--dialect", "postgresql"]
}
# Ent (Go)
env "<name>" {
schema {
src = "ent://ent/schema"
}
}
# Sequelize (Node.js)
data "external_schema" "sequelize" {
program = ["npx", "@ariga/atlas-provider-sequelize", "load", "--path", "./models", "--dialect", "postgres"]
}
# TypeORM (TypeScript)
data "external_schema" "typeorm" {
program = ["npx", "@ariga/atlas-provider-typeorm", "load", "--path", "./entities", "--dialect", "postgres"]
}
```
Wire into an environment:
```hcl
env "<name>" {
schema {
src = data.external_schema.<orm>.url
}
}
```
## Composite Schema (Pro)
Combine multiple schema sources into one:
```hcl
data "composite_schema" "app" {
schema "users" {
url = data.external_schema.auth_service.url
}
schema "graph" {
url = "ent://ent/schema"
}
schema "shared" {
url = "file://schema/shared.hcl"
}
}
```
## Dev-Database Dialects
The dev URL format depends on whether your project uses **schema-scoped** or **database-scoped** migrations. Getting this wrong causes errors like `ModifySchema is not allowed` or silently drops database-level objects (extensions, event triggers) from migrations.
**Schema-scoped** (single schema — most common): include the database name and schema scope so Atlas creates objects in the correct schema. Use this when all tables live in one schema (e.g., `public`).
| Dialect | Dev URL (schema-scoped) |
|------------|------------------------------------------------------|
| MySQL | `docker://mysql/8/dev` |
| MariaDB | `docker://maria/latest/dev` |
| PostgreSQL | `docker://postgres/17/dev?search_path=public` |
| SQLite | `sqlite://dev?mode=memory` |
| SQL Server | `docker://sqlserver/2022-latest/dev?mode=schema` |
| ClickHouse | `docker://clickhouse/23.11/dev` |
**Database-scoped** (multiple schemas or database-level objects): omit the schema scope so Atlas can manage multiple schemas and detect database-level objects like extensions and event triggers.
| Dialect | Dev URL (database-scoped) |
|------------|------------------------------------------------------|
| MySQL | `docker://mysql/8` |
| MariaDB | `docker://maria/latest` |
| PostgreSQL | `docker://postgres/17/dev` |
| SQL Server | `docker://sqlserver/2022-latest/dev?mode=database` |
| ClickHouse | `docker://clickhouse/23.11` |
**PostgreSQL with extensions** — use PostGIS or pgvector images when the schema uses those extensions:
```
docker://postgis/latest/dev?search_path=public
docker://pgvector/pg17/dev?search_path=public
```
**How to choose:** Check the project's `atlas.hcl` or target database URL. If it includes `search_path=public` (Postgres) or a specific database name (MySQL), use schema-scoped. If the project manages multiple schemas, extensions, or event triggers, use database-scoped.
See https://atlasgo.io/concepts/dev-database for additional drivers and options.
# Atlas Cloud CLI
`atlas cloud` commands read and manage resources in **Atlas Cloud** (the Atlas Registry and deployment tracking). They do **not** connect to databases directly — they report what Atlas Cloud knows about repos, registered databases (targets), and deployment events.
Use them for **operational visibility** and **pre-flight checks**. Use local commands (`atlas migrate status`, `atlas migrate apply`, `atlas schema diff`) to inspect or change an actual database.
## Prerequisites
1. **Atlas CLI** — `atlas cloud` is not only available in the community version.
2. **Authentication** — run before any cloud command:
```bash
atlas whoami # verify current org
atlas login [org] # interactive login
atlas login --token "$TOKEN" # CI / non-interactive
```
`ATLAS_TOKEN` env var is also accepted by `atlas login`.
3. If `atlas whoami` fails, stop and authenticate before proceeding.
## Command Reference
```
atlas cloud
├── repo
│ ├── list
│ ├── describe
│ ├── create
│ └── lingraph
├── database
│ ├── list
│ └── describe
└── migration
├── list
└── describe
```
### `atlas cloud repo`
Manage Atlas Registry repositories (schema or migration directory artifacts).
| Command | Purpose |
|---------|---------|
| `repo list` | List all repos with per-repo database counts (synced / failed / pending) |
| `repo describe` | Details for one repo: slug, type, driver, URL, database counts |
| `repo create` | Create an empty repo in the registry (before first push); idempotent if the repo already exists |
| `repo lingraph` | Print the migration lineage graph for a repo |
**Identify a repo** (describe): exactly one of `--id`, `--slug`, or `--name`.
**Create flags** (all required):
- `--type schema` (or `s`) — declarative schema repo
- `--type migration_directory` (or `m`) — versioned migration repo
- `--name <name>` — repo name
- `--driver <driver>` — e.g. `postgres`, `mysql`, `sqlite`, `mssql`, `clickhouse`, `cockroach`
**Lineage graph**:
```bash
atlas cloud repo lingraph --slug <slug>
atlas cloud repo lingraph --slug <slug> --open-lineage # OpenLineage format
```
### `atlas cloud database`
Query **registered migration/schema targets** (databases linked to Atlas Cloud).
| Command | Purpose |
|---------|---------|
| `database list` | List all cloud-tracked databases |
| `database describe` | Details for one database |
**Output fields**: `ID`, `Name`, `RepoName`, `EnvName`, `Status`, `CurrentVersion`, `LastDeploymentTime`.
**Database status** (`Status` column):
| Status | Meaning |
|--------|---------|
| `SYNCED` | Target matches the expected repo version |
| `PENDING` | Deployment or sync is in progress / not yet complete |
| `FAILED` | Last sync or deployment failed for this target |
**Filters** (list):
- `--env-name <env>` — filter by environment name (matches `env` blocks in `atlas.hcl`)
**Identify a database** (describe): exactly one of `--id` or `--ext-id`.
### `atlas cloud migration`
Query **deployment events** (each time migrations or schema were applied to targets).
| Command | Purpose |
|---------|---------|
| `migration list` | List deployment events with filters |
| `migration describe` | Details for one event |
**Migration event status**:
| Status | Meaning |
|--------|---------|
| `PASSED` | Deployment succeeded |
| `FAILED` | Deployment failed |
| `NO_ACTION` | No changes were needed |
| `DRY_RUN` | Dry-run only, nothing applied |
**Filters** (list):
- `--status <status>` — repeatable; values: `PASSED`, `FAILED`, `NO_ACTION`, `DRY_RUN`
- `--repo <slug>` — filter by repository slug
- `--name <substring>` — filter by database name (contains match)
- `--env-name <env>` — filter by environment
**Describe**: `--id <migration-event-id>` (required).
## Common Flags
| Flag | Commands | Purpose |
|------|----------|---------|
| `--format <template>` | list, describe (except lingraph) | Go template output; use `json` helper for machine-readable — `--format '{{json .}}'` |
| `--page <n>` | list commands | Page number to fetch (default 1); see **Pagination** below |
### Pagination
List commands (`repo list`, `database list`, `migration list`) return at most **20 records per page**. Each response ends with a footer:
```
--------------------------------
Page: 1 Page Size: 20 Total: 45
```
| Footer field | Meaning |
|--------------|---------|
| `Page` | Current page (1-based); matches the `--page` flag value |
| `Page Size` | Fixed at 20 records per page (not configurable via CLI) |
| `Total` | Total records matching the current filters across all pages |
**Are there more pages?** When `Total > Page Size` (i.e. `Total > 20`). Compute the number of pages:
```
total_pages = ceil(Total / Page Size)
```
Example: `Total: 45`, `Page Size: 20` → `ceil(45 / 20) = 3` pages.
**When to fetch the next page:**
- If `Page < total_pages`, more records exist — re-run the same command with `--page <Page + 1>`.
- If `Page == total_pages`, you have all records for the current filters.
- If `Total <= Page Size`, everything fits on one page; no further requests needed.
**Example** (45 records across 3 pages):
```bash
atlas cloud database list # page 1: records 1–20
atlas cloud database list --page 2 # page 2: records 21–40
atlas cloud database list --page 3 # page 3: records 41–45
```
With `--format '{{ json . }}'`, pagination metadata is on the `PageInfo` field (`Page`, `PageSize`, `Total`). Use it in scripts to decide whether to request another page.
**Examples**:
```bash
atlas cloud database list
atlas cloud migration list --status FAILED
```
## When to Use Which Command
| User goal | Start with |
|-----------|------------|
| Is a repo healthy across all its databases? | `atlas cloud repo list` or `repo describe --slug <slug>` |
| What version is a database on in Atlas Cloud? | `atlas cloud database list --env-name <env>` or `database describe` |
| Did a recent deployment fail? | `atlas cloud migration list --status FAILED` |
| What happened in a specific deployment? | `atlas cloud migration describe --id <id>` |
| Create a registry repo before first push | `atlas cloud repo create --type m --name <n> --driver postgres` |
| Check object dependencies | `atlas cloud repo lingraph --slug <slug>` |
| Which org am I connected to? | `atlas whoami` |
| Can I push a schema change or migration to database X? | `atlas cloud database list` then `atlas cloud database describe --id <id>` using the id of database X from the list |
## Agent Workflows
### Pre-deployment readiness
Before recommending `atlas migrate apply` or a CI deploy, check Atlas Cloud state:
```
Task Progress:
- [ ] Verify auth: atlas whoami
- [ ] Check target status: atlas cloud database list --env-name <env>
- [ ] Check for failed deployments: atlas cloud migration list --status FAILED --env-name <env>
- [ ] Check repo health: atlas cloud repo describe --slug <slug>
```
**Decision rules**:
- Any database with `Status=FAILED` → investigate before applying. Run `migration list --status FAILED` filtered to that env/repo, then `migration describe` on the event ID.
- Any database with `Status=PENDING` → a deployment may be in flight; wait or confirm before starting another.
- All targets `SYNCED` and no recent `FAILED` events → cloud state looks healthy. Still run local checks (`atlas migrate status`, lint) before applying.
- `repo describe` shows `Databases Failed > 0` → at least one target in that repo is unhealthy; drill into `database list` and `migration list`.
### Investigate a failed deployment
1. `atlas cloud migration list --status FAILED --repo <slug>` (add `--env-name` or `--name` to narrow)
2. `atlas cloud migration describe --id <id>` for version, completion time, and multi-target results
3. `atlas cloud database describe --id <id>` on affected targets to see current version vs expected
4. Use local `atlas migrate status --env <env>` to compare the live database revision table against cloud state
### Audit environments
Read `atlas.hcl` first to find environment names (`env` block names). For each environment you want to compare, run:
```bash
atlas cloud database list --env-name <env>
atlas cloud migration list --env-name <env>
```
Repeat for every relevant `env` in the project (e.g. dev, staging, prod — names vary). Compare `CurrentVersion` across environments to spot version skew.
### Set up a new registry repo
1. `atlas cloud repo create --type migration_directory --name <name> --driver postgres`
2. Note the returned `Slug` and `URL`
3. Reference in `atlas.hcl`: `migration { dir = "atlas://<slug>" }`
4. Push migrations with `atlas migrate push` (separate from `atlas cloud`)
## Cloud vs Local Commands
| Concern | Atlas Cloud (`atlas cloud …`) | Local (`atlas migrate/schema …`) |
|---------|-------------------------------|-----------------------------------|
| Registry repos & artifacts | ✅ | `migrate push`, `schema push` |
| Registered target status | ✅ | — |
| Deployment event history | ✅ | — |
| Live database revision table | — | `migrate status` |
| Schema drift vs desired state | — | `schema diff`, `migrate lint` |
| Apply changes to a database | — | `migrate apply`, `schema apply` |
Cloud commands answer **"what does Atlas Cloud know?"** Local commands answer **"what is actually in the database?"** Use both when validating readiness.
## Reporting Results to the User
When summarizing cloud command output:
1. State the org (`atlas whoami`) and filters used
2. Highlight `FAILED` / `PENDING` statuses prominently
3. For migrations, include `Version`, `Status`, `CompletedAt`, and `TargetsSucceeded/TargetsTotal` when present
4. Distinguish cloud-reported state from local database state — recommend local verification when the user plans to apply changes
5. For list commands, read the pagination footer (or `PageInfo` in JSON). If `Total > Page Size`, compute `total_pages = ceil(Total / Page Size)` and fetch remaining pages with `--page 2`, `--page 3`, etc. until `Page == total_pages` before concluding the result set is complete
## Error Handling
| Error | Action |
|-------|--------|
| `'atlas login' is required` | Run `atlas login` or set token |
| `repository not found` / `database not found` / `migration not found` | Verify identifier; try `list` first to get correct ID/slug |
| `invalid --status value` | Use `PASSED`, `FAILED`, `NO_ACTION`, or `DRY_RUN` |
| `invalid --type` | Use `schema`/`s` or `migration_directory`/`m` |
| Mutually exclusive flags (`--id` vs `--slug`) | Provide exactly one identifier |
Commit this to your repository so all team members benefit from consistent workflows.
What the Skill Covers
AI agents are great at writing code, but generating database migrations is a different challenge. As schemas grow larger and more complex, ensuring migrations are deterministic, predictable, and aligned with company policies becomes critical.
Atlas lets AI tools focus on editing the schema while providing the infrastructure for:
- Schema Validation - verifying schema definitions are syntactically and semantically correct before generating migrations
- Migration Generation - producing correct, safe, and deterministic migrations automatically
- Migration Validation - ensuring migrations are semantically correct and follow best practices
- Policy Enforcement - applying organizational rules for what changes are allowed and how they should be applied
- Unit Testing - AI tools can write logic (functions, views, queries) along with tests, while Atlas executes them, reports failures, and lets the AI fix issues automatically
- Data Migration Testing - AI tools can generate data migrations, seed data, run tests, detect errors, and guide the AI in resolving them
- Atlas Cloud Operations - pre-deployment readiness checks, deployment event investigation, and registry repo management via
atlas cloudcommands
Skills package this knowledge into a portable SKILL.md file that works across Claude, Codex, Cursor,
and other agents. The agent loads the skill when database operations are requested, then follows the
workflows and commands defined in the skill.
Claude Code supports additional integration methods beyond skills, including subagents, slash commands, and hooks. See the Claude Code page for the full guide.
Example Usage
When a user asks the agent to add a column to a table, the agent follows the skill's workflow:
User: Add an email column to the users table
Agent: I'll use Atlas to add this column safely.
1. Inspecting current schema...
$ atlas schema inspect --env dev
2. Adding column to schema file...
[edits schema.hcl]
3. Validating schema...
$ atlas schema validate --env dev
✓ Schema is valid
4. Generating migration...
$ atlas migrate diff --env dev "add_users_email"
Created: migrations/20250101120000_add_users_email.sql
5. Linting migration...
$ atlas migrate lint --env dev --latest 1
✓ No issues found
6. Ready to apply (dry-run first)...
$ atlas migrate apply --env dev --dry-run
Full Skill Content
View full SKILL.md
---
name: atlas
description: "Database schema management and migrations with Atlas CLI. Use when: generating migrations, diffing schemas, linting or testing migrations, applying schema changes, inspecting databases, working with atlas.hcl, schema.hcl, or ORM schemas (GORM, Drizzle, SQLAlchemy, Django, Ent, Sequelize, TypeORM), validating schema definitions, or checking Atlas Cloud registry and deployment status."
---
# Atlas Schema Migrations
## Security
Never hardcode credentials. Use environment variables:
```hcl
env "prod" {
url = getenv("DATABASE_URL")
}
```
## Quick Reference
Use `--help` on any command for comprehensive docs and examples:
```bash
atlas migrate diff --help
```
Always use `--env` to reference configurations from `atlas.hcl` — this avoids passing
database credentials to the LLM context.
```bash
# Common
atlas schema inspect --env <name> # Inspect schema
atlas schema validate --env <name> # Validate schema syntax/semantics
atlas schema diff --env <name> # Compare schemas
atlas schema lint --env <name> # Check schema policies
atlas schema test --env <name> # Test schema
# Declarative workflow
atlas schema plan --env <name> # Plan schema changes
atlas schema apply --env <name> --dry-run # Preview changes
atlas schema apply --env <name> # Apply schema changes
# Versioned workflow
atlas migrate diff --env <name> "migration_name" # Generate migration
atlas migrate lint --env <name> --latest 1 # Validate migration
atlas migrate test --env <name> # Test migration
atlas migrate apply --env <name> --dry-run # Preview changes
atlas migrate apply --env <name> # Apply migration
atlas migrate status --env <name> # Check status
```
## Choosing a Workflow
```
Schema change needed
├─ Project has migrations/ dir or migration config in atlas.hcl?
│ ├─ Yes → Versioned: migrate diff → lint → test → apply
│ └─ No → Declarative: schema apply --dry-run → apply
├─ Iterating on local database?
│ └─ Use schema apply --auto-approve for fast edit-apply cycles
└─ Not sure → Read atlas.hcl first
```
**Tip:** `atlas schema apply` applies schema changes directly to a local database without generating migration files. This is useful for fast iteration during development — edit the schema, run `schema apply`, and see the result immediately.
## Example
```
User: Add an email column to the users table
Agent steps:
1. atlas schema inspect --env dev # understand current state
2. Edit schema source file # add email column
3. atlas schema validate --env dev # verify syntax
4. atlas migrate diff --env dev "add_email" # generate migration
5. atlas migrate lint --env dev --latest 1 # check for issues
6. atlas migrate apply --env dev --dry-run # preview before applying
```
## Core Concepts
### Configuration File (atlas.hcl)
Always read the project's `atlas.hcl` first — it contains environment configurations:
```hcl
env "<name>" {
url = getenv("DATABASE_URL")
dev = "docker://postgres/15/dev?search_path=public"
migration {
dir = "file://migrations"
}
schema {
src = "file://schema.hcl"
}
}
```
### Dev Database
Atlas uses a temporary "dev-database" to process and validate schemas. The URL format depends on whether you work with a **single schema** or **multiple schemas**:
```bash
# Schema-scoped (single schema — most common)
--dev-url "docker://mysql/8/dev"
--dev-url "docker://postgres/15/dev?search_path=public"
--dev-url "sqlite://dev?mode=memory"
--dev-url "docker://sqlserver/2022-latest/dev?mode=schema"
# Database-scoped (multiple schemas, extensions, or event triggers)
--dev-url "docker://mysql/8"
--dev-url "docker://postgres/15/dev"
--dev-url "docker://sqlserver/2022-latest/dev?mode=database"
```
**Important:** Using the wrong scope causes errors (`ModifySchema is not allowed`) or silently drops database-level objects (extensions, event triggers) from migrations. Match the dev URL scope to the project's target database URL. For PostGIS or pgvector schemas, use `docker://postgis/latest/dev` or `docker://pgvector/pg17/dev`.
If the schema depends on extensions or external objects, use a `docker` block with a `baseline`:
```hcl
docker "postgres" "dev" {
image = "postgres:15"
schema = "public"
baseline = <<SQL
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
SQL
}
env "local" {
src = "file://schema.hcl"
dev = docker.postgres.dev.url
}
```
## Workflows
### 1. Schema Inspection
Start with a high-level overview before diving into details. The default output is HCL.
Use `--format "{{ json . }}"` for JSON or `--format "{{ sql . }}"` for SQL.
```bash
# List tables (overview first, JSON output)
atlas schema inspect --env <name> --format "{{ json . }}" | jq ".schemas[].tables[].name"
# Full SQL schema
atlas schema inspect --env <name> --format "{{ sql . }}"
# Filter with --include/--exclude (useful for large schemas)
atlas schema inspect --env <name> --include "users_*" # Only matching tables
atlas schema inspect --env <name> --exclude "*_backup" # Skip matching tables
atlas schema inspect --env <name> --exclude "*[type=trigger]" # Skip triggers
# Open visual ERD in browser (requires atlas login)
atlas schema inspect --env <name> -w
```
### 2. Schema Comparison (Diff)
Compare any two schema states:
```bash
# Compare current state to desired schema
atlas schema diff --env <name>
# Compare specific sources
atlas schema diff --env <name> --from file://migrations --to file://schema.hcl
```
### 3. Migration Generation
Generate migrations from schema changes:
```bash
# Generate migration from schema diff
atlas migrate diff --env <name> "add_users_table"
# With explicit parameters
atlas migrate diff \
--dir file://migrations \
--dev-url docker://postgres/15/dev \
--to file://schema.hcl \
"add_users_table"
```
### 4. Schema Validation
Validate schema definitions before generating migrations:
```bash
# Validate schema syntax and semantics
atlas schema validate --env <name>
# Validate against dev database
atlas schema validate --dev-url docker://postgres/15/dev --url file://schema.hcl
```
If valid, exits successfully. If invalid, prints detailed error (unresolved references, syntax issues, unsupported attributes).
### 5. Migration Linting
```bash
atlas migrate lint --env <name> --latest 1 # Lint latest migration
atlas migrate lint --env ci # Lint since git branch
atlas schema lint --env <name> # Check schema policies
```
Fixing lint issues:
- Unapplied migrations: Edit file, then `atlas migrate hash --env <name>`
- Applied migrations: Create corrective migration (never edit directly)
### 6. Migration Testing
```bash
atlas migrate test --env <name> # Requires atlas login
atlas whoami # Check login status first
```
### 7. Applying Migrations
```bash
atlas migrate apply --env <name> --dry-run # Always preview first
atlas migrate apply --env <name> # Apply
atlas migrate status --env <name> # Verify
```
## Standard Workflow
1. `atlas schema inspect --env <name>` — Understand current state
2. Edit schema files
3. `atlas schema validate --env <name>` — Check syntax
4. `atlas migrate diff --env <name> "change_name"` — Generate migration
5. `atlas migrate lint --env <name> --latest 1` — Validate
6. `atlas migrate test --env <name>` — Test (requires login)
7. If issues: edit migration, then `atlas migrate hash`
8. `atlas migrate apply --env <name> --dry-run` then apply
## Schema Sources
For HCL schemas, ORM integrations (GORM, Drizzle, SQLAlchemy, Django, Ent, Sequelize, TypeORM),
composite schemas, and dev-database dialect URLs, see `references/schema-sources.md`.
## Atlas Cloud
For registry repos, registered database targets, deployment events, pre-flight checks, and
cloud vs local command guidance, see `references/cloud.md`.
## Onboarding an Existing Project
### Baseline an existing database
To start managing an existing database with versioned migrations:
```bash
# 1. Export current schema to code
atlas schema inspect -u '<database-url>' --format '{{ sql . | split | write "src" }}'
# 2. Generate a baseline migration from the exported schema
atlas migrate diff "baseline" --to "file://src" --dev-url '<dev-url>'
# 3. Mark baseline as applied on existing databases (use version from filename)
atlas migrate apply --url '<database-url>' --baseline '<version>'
```
The baseline migration captures the current state without executing it on existing databases.
On new databases, it runs in full to create the initial schema.
## Troubleshooting
```bash
# Check installation and login
atlas version
atlas whoami
# Repair migration integrity after manual edits
atlas migrate hash --env <name>
```
**Missing driver error**: Ensure `--url` or `--dev-url` is correctly specified.
## Key Rules
1. Read `atlas.hcl` first — use environment names from config
2. Never hardcode credentials — use `getenv()`
3. Run `atlas schema validate` after schema edits
4. Always lint before applying migrations
5. Always dry-run before applying
6. Run `atlas migrate hash` after editing migration files
7. Use `atlas login` to unlock views, triggers, functions, ERD, and migration testing
8. Write migration tests for data migrations
9. Never ignore lint errors — fix them or get user approval
10. Before production deploys, check Atlas Cloud state (`atlas cloud database list`, `migration list --status FAILED`) — see `references/cloud.md`
## Documentation
- [CLI Reference](https://atlasgo.io/cli-reference)
- [Versioned Migrations](https://atlasgo.io/versioned/diff)
- [Declarative Workflow](https://atlasgo.io/declarative/apply)
- [Migration Linting](https://atlasgo.io/versioned/lint)
- [Migration Testing](https://atlasgo.io/testing/migrate)
- [Onboard Existing Database](https://atlasgo.io/versioned/import)
- [ORM Integrations](https://atlasgo.io/guides/orms)
- [Dev Database](https://atlasgo.io/concepts/dev-database)