CI/CD for Databases on CircleCI - Versioned Workflow
CircleCI is a popular CI/CD platform that allows you to automatically build, test, and deploy your code. Combined with Atlas, you can manage database schema changes with confidence.
In this guide, we will demonstrate how to use CircleCI and Atlas to set up CI/CD pipelines for your database schema changes using the versioned migrations workflow.
Prerequisites
Installing Atlas
- macOS + Linux
- Homebrew
- Docker
- Windows
- CI
- Manual Installation
To download and install the latest release of the Atlas CLI, simply run the following in your terminal:
curl -sSf https://atlasgo.sh | sh
Get the latest release with Homebrew:
brew install ariga/tap/atlas
To pull the Atlas image and run it as a Docker container:
docker pull arigaio/atlas
docker run --rm arigaio/atlas --help
If the container needs access to the host network or a local directory, use the --net=host flag and mount the desired
directory:
docker run --rm --net=host \
-v $(pwd)/migrations:/migrations \
arigaio/atlas migrate apply
--url "mysql://root:pass@:3306/test"
Download the latest release and move the atlas binary to a file location on your system PATH.
GitHub Actions
Use the setup-atlas action to install Atlas in your GitHub Actions workflow:
- uses: ariga/setup-atlas@v0
with:
cloud-token: ${{ secrets.ATLAS_CLOUD_TOKEN }}
Other CI Platforms
For other CI/CD platforms, use the installation script. See the CI/CD integrations for more details.
After installing Atlas locally, log in to your organization by running the following command:
atlas login
Creating a bot token and CircleCI context
To report CI run results to Atlas Cloud, create an Atlas Cloud bot token by following these instructions and copy it.
Next, we'll create a CircleCI context to securely store environment variables that will be shared across jobs:
- In CircleCI, go to Organization Settings -> Contexts
- Click Create Context and name it
dev(this matches the context used in our example configuration) - Click on the newly created
devcontext - Add the following environment variables:
ATLAS_TOKEN: Your Atlas Cloud bot token (how to create) - requiredDATABASE_URL: The URL (connection string) of your target database (URL format guide) - requiredGITHUB_TOKEN: GitHub personal access token withreposcope (how to create) - optional, needed for PR commentsGITHUB_REPOSITORY: Your GitHub repository in the formatowner/repo(e.g.,ariga/atlas) - required for PR comments
Using a context allows you to manage these sensitive variables in one place and reuse them across multiple projects and workflows.
Versioned Migrations Workflow
In the versioned workflow, changes to the schema are represented by a migration directory in your codebase. Each file in this directory represents a transition to a new version of the schema.
Based on our blueprint for Modern CI/CD for Databases, our pipeline will:
- Lint new migration files whenever a pull request is opened.
- Push the migration directory to the Schema Registry when changes are merged to the main branch.
- Apply new migrations to our database.
In this guide, we will walk through each of these steps and set up a CircleCI configuration to automate them.
The full source code for this example can be found in the atlas-examples/versioned repository.
Defining the desired schema
First, define your desired database schema. Create a file named schema.sql with the following content:
CREATE TABLE "users" (
"id" bigserial PRIMARY KEY,
"name" text NOT NULL,
"active" boolean NOT NULL,
"address" text NOT NULL,
"nickname" text NOT NULL,
"nickname2" text NOT NULL,
"nickname3" text NOT NULL
);
CREATE INDEX "users_active" ON "users" ("active");
Creating the Atlas configuration file
Create a configuration file for Atlas named atlas.hcl with the following content:
variable "database_url" {
type = string
default = getenv("DATABASE_URL")
description = "URL to the target database to apply changes"
}
env "dev" {
src = "file://schema.sql"
url = var.database_url
dev = "docker://postgres/15/dev?search_path=public"
migration {
dir = "file://migrations"
}
diff {
concurrent_index {
add = true
drop = true
}
}
}
Generating your first migration
Now, generate your first migration by comparing your desired schema with the current (empty) migration directory:
atlas migrate diff initial --env dev
This command will automatically create a migrations directory with a migration file containing the SQL statements needed to create the users table and index, as defined in our file linked at src in the dev environment.
Pushing a migration directory to Atlas Cloud
Run the following command from the parent directory of your migration directory to create a "migration directory" repository in your Atlas Cloud organization:
atlas migrate push circleci-atlas-action-versioned-demo --env dev
This command pushes the migrations directory linked in the migration dir field in the dev environment defined in our atlas.hcl to a project in the Schema Registry called circleci-atlas-action-versioned-demo.
Atlas will print a URL leading to your migrations on Atlas Cloud. You can visit this URL to view your migrations.
Setting up CircleCI
Create a .circleci/config.yml file in the root of your repository with the following content:
version: 2.1
orbs:
atlas-orb: ariga/atlas-orb@0.3.1
jobs:
lint-migrations:
docker:
- image: cimg/base:current
- image: cimg/postgres:15.0
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
steps:
- checkout
- run:
name: Wait for Postgres
command: dockerize -wait tcp://127.0.0.1:5432 -timeout 60s
- atlas-orb/setup:
version: "latest"
- atlas-orb/migrate_lint:
env: dev
dir_name: "circleci-atlas-action-versioned-demo"
dev_url: "postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable&search_path=public"
push-and-apply-migrations:
docker:
- image: cimg/base:current
- image: cimg/postgres:15.0
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
steps:
- checkout
- run:
name: Wait for Postgres
command: dockerize -wait tcp://127.0.0.1:5432 -timeout 60s
- atlas-orb/setup:
version: "latest"
- atlas-orb/migrate_push:
env: dev
dir_name: "circleci-atlas-action-versioned-demo"
dev_url: "postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable&search_path=public"
- atlas-orb/migrate_apply:
env: dev
dir: "atlas://circleci-atlas-action-versioned-demo"
workflows:
version: 2
atlas-workflow:
jobs:
- lint-migrations:
context: dev
filters:
branches:
ignore: main
- push-and-apply-migrations:
context: dev
filters:
branches:
only: main
This configuration uses main as the default branch name. If your GitHub repository uses a different default branch (such as master), update the workflow filters accordingly:
filters:
branches:
only: master # Change to match your default branch
Let's break down what this pipeline configuration does:
- The
lint-migrationsjob runs on every pull request (branches that are notmain). When new migrations are detected, Atlas will lint them and post a report as a comment on the pull request. This helps you catch issues early in the development process.

-
After the pull request is merged into the main branch, the
push-and-apply-migrationsjob will push the new state of the migration directory to the Schema Registry on Atlas Cloud. -
The
migrate_applystep will then deploy the new migrations to your database.
Testing our pipeline
Let's take our pipeline for a spin:
- Locally, create a new branch and add a new migration with
atlas migrate new --edit. Paste the following in the editor:schema.sqlDROP INDEX "users_active"; - Commit and push the changes.
- In GitHub, create a pull request for the branch you just pushed.
- View the lint report generated by Atlas. Follow the links to see the changes visually on Atlas Cloud.
- Merge the pull request.
- When the pipeline has finished running, check your database to verify that the changes were applied.
Wrapping up
In this guide, we demonstrated how to use CircleCI with Atlas to set up a modern CI/CD pipeline for versioned database migrations. Here's what we accomplished:
- Automated migration linting on every pull request to catch issues early
- Centralized migration management by pushing to Atlas Cloud's Schema Registry
- Automated deployments to your target database when changes are merged
For more information on the versioned workflow, see the Versioned Migrations documentation.
Next steps
- Learn about Atlas Cloud for enhanced collaboration
- Explore migration testing to validate your migrations
- Read about declarative migrations as an alternative workflow
- Check out the CircleCI Orbs reference for all available actions