Skip to main content

Atlas Terraform Provider Quickstart

Intro

In this guide we will quickly go through setting up the Atlas Terraform Provider locally and demonstrate some of its basic features.

Installing Terraform

To get started, you will need Terraform installed on your system. For macOS users, you can install it using Homebrew:

brew tap hashicorp/tap
brew install hashicorp/tap/terraform

For other operating systems, follow the instructions on the official Terraform website.

Set up a local database

Next, we will set up a MySQL database that we'll manage using the Atlas Terraform Provider.

This step requires Docker to be installed on your system. If you don't have Docker installed, you can find installation instructions on the Docker website.

Run the following command to start a MySQL container with Docker:

docker run -d --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=pass -e MYSQL_DATABASE=myapp mysql:8

Verify the MySQL container is ready before proceeding:

docker exec mysql mysql -uroot -ppass -e "SELECT 1"

If the command returns a result, MySQL is ready to use.

Install the Atlas Terraform Provider

Create a file named main.tf with the following content to configure the Atlas provider:

main.tf
terraform {
required_providers {
atlas = {
source = "ariga/atlas"
version = "~> 0.9.7"
}
}
}

provider "atlas" {
dev_url = "docker://mysql/8/myapp"
}

The dev_url configuration uses the docker:// driver to automatically create a temporary container for Atlas's dev-database. This ephemeral container is separate from our manually created MySQL container, which is the actual database we're managing.

Now initialize Terraform to download the provider:

terraform init

This will produce output similar to:

Initializing the backend...
Initializing provider plugins...
- Finding ariga/atlas versions matching "~> 0.9.7"...
- Installing ariga/atlas v0.9.7...
- Installed ariga/atlas v0.9.7 (self-signed, key ID 149262AD73B30060)
...

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
...

Define a schema in SQL

We will create a schema.sql file to define a simple users table with id and name columns.

schema.sql
create table users (
id int not null auto_increment primary key,
name varchar(255) not null
);

Apply a schema

Now we'll create a complete Terraform configuration to apply this schema to our database. Update your main.tf file to include:

main.tf
terraform {
required_providers {
atlas = {
source = "ariga/atlas"
version = "~> 0.9.7"
}
}
}

provider "atlas" {
dev_url = "docker://mysql/8/myapp"
}

data "atlas_schema" "sql" {
src = "file://${path.module}/schema.sql"
}

resource "atlas_schema" "mysql" {
url = "mysql://root:pass@localhost:3306/myapp"
hcl = data.atlas_schema.sql.hcl
}

This configuration includes two important parts:

  1. The atlas_schema data source that loads and normalizes the schema from our SQL file.
  2. The atlas_schema resource that applies the schema to our target MySQL database.

To apply the schema, run:

terraform apply

This command will show a plan of what changes will be made to the database:

data.atlas_schema.sql: Reading...
data.atlas_schema.sql: Read complete after 2s [id=p93KLX2q4UI326LN/4cssQ]

Terraform will perform the following actions:

# atlas_schema.mysql will be created
+ resource "atlas_schema" "mysql" {
+ hcl = <<-EOT
table "users" {
schema = schema.myapp
column "id" {
null = false
type = int
auto_increment = true
}
column "name" {
null = false
type = varchar(255)
}
primary_key {
columns = [column.id]
}
}
schema "myapp" {
charset = "utf8mb4"
collate = "utf8mb4_0900_ai_ci"
}
EOT
+ id = (known after apply)
+ url = (sensitive value)
}

Plan: 1 to add, 0 to change, 0 to destroy.

The following SQL statements will be executed:

CREATE TABLE `users` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;

Type "yes" when prompted to apply these changes.

To verify that the schema was applied correctly, you can connect to the MySQL database and inspect the tables:

docker exec -it mysql mysql -uroot -ppass myapp -e "DESCRIBE users;"

This command will show the schema of the users table:

+-------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
+-------+--------------+------+-----+---------+----------------+

Great! You have successfully applied a schema to a MySQL database using the Atlas Terraform Provider.

Evolve the schema

Let's modify our schema to add a new table and a relationship between tables. Update the schema.sql file with the following content:

schema.sql
create table `groups` (
id int not null auto_increment primary key,
name varchar(255) not null
);

create table `users` (
id int not null auto_increment primary key,
name varchar(255) not null,
group_id int not null,
foreign key (group_id) references `groups` (id)
);

Now we've added a groups table and modified the users table to include a foreign key reference to it.

Apply the updated schema:

terraform apply

The output will show what changes will be made to your database:

data.atlas_schema.sql: Reading...
data.atlas_schema.sql: Read complete after 2s [id=Qhci62i6CFYRQ2CmUOjMeA]
atlas_schema.mysql: Refreshing state... [id=3bc3da59-2110-1460-9495-d886c8d7303b]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
~ update in-place

Terraform will perform the following actions:

# atlas_schema.mysql will be updated in-place
~ resource "atlas_schema" "mysql" {
~ hcl = <<-EOT
+ table "groups" {
+ schema = schema.myapp
+ column "id" {
+ null = false
+ type = int
+ auto_increment = true
+ }
+ column "name" {
+ null = false
+ type = varchar(255)
+ }
+ primary_key {
+ columns = [column.id]
+ }
+ }
table "users" {
schema = schema.myapp
column "id" {
null = false
type = int
auto_increment = true
}
column "name" {
null = false
type = varchar(255)
}
+ column "group_id" {
+ null = false
+ type = int
+ }
primary_key {
columns = [column.id]
}
+ foreign_key "users_ibfk_1" {
+ columns = [column.group_id]
+ ref_columns = [table.groups.column.id]
+ on_update = NO_ACTION
+ on_delete = NO_ACTION
+ }
+ index "group_id" {
+ columns = [column.group_id]
+ }
}
schema "myapp" {
charset = "utf8mb4"
collate = "utf8mb4_0900_ai_ci"
}
EOT
id = "3bc3da59-2110-1460-9495-d886c8d7303b"
# (1 unchanged attribute hidden)
}

Plan: 0 to add, 1 to change, 0 to destroy.

│ Warning: Atlas Plan

│ with atlas_schema.mysql,
│ on main.tf line 18, in resource "atlas_schema" "mysql":
│ 18: resource "atlas_schema" "mysql" {

│ The following SQL statements will be executed:


│ CREATE TABLE `groups` (
│ `id` int NOT NULL AUTO_INCREMENT,
│ `name` varchar(255) NOT NULL,
│ PRIMARY KEY (`id`)
│ ) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
│ ALTER TABLE `users` ADD COLUMN `group_id` int NOT NULL, ADD INDEX `group_id` (`group_id`), ADD CONSTRAINT `users_ibfk_1` FOREIGN KEY
│ (`group_id`) REFERENCES `groups` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION;



Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.

To verify the schema changes, connect to the MySQL database and inspect the tables again:

docker exec -it mysql mysql -uroot -ppass myapp -e "SHOW TABLES; DESCRIBE users; DESCRIBE \`groups\`;"

You should see both tables with their updated schemas, including the foreign key relationship:

+-----------------+
| Tables_in_myapp |
+-----------------+
| groups |
| users |
+-----------------+
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| group_id | int | NO | MUL | NULL | |
+----------+--------------+------+-----+---------+----------------+
+-------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
+-------+--------------+------+-----+---------+----------------+

Working with an existing database

When working with an existing database that wasn't initially managed by Atlas, you can inspect the current database schema using the Atlas CLI and use it as your baseline. Here's how:

  1. Inspect the current database schema using the Atlas CLI:
atlas schema inspect -u mysql://root:pass@localhost:3306/your_database > current-schema.my.hcl

This command creates an HCL representation of your database schema in the file current-schema.my.hcl.

  1. Use this HCL file in your Terraform configuration:
main.tf
terraform {
required_providers {
atlas = {
source = "ariga/atlas"
version = "~> 0.9.7"
}
}
}

provider "atlas" {
dev_url = "docker://mysql/8/myapp"
}

data "atlas_schema" "current" {
src = "file://path/to/current-schema.my.hcl"
}

resource "atlas_schema" "mysql" {
url = "mysql://root:pass@localhost:3306/myapp"
hcl = data.atlas_schema.current.hcl
}
  1. Make modifications to the current-schema.my.hcl file to define your desired schema state and apply the changes through Terraform.

Next Steps

Atlas offers two workflows for database schema management:

  • Declarative Workflow - Define the desired schema state and let Atlas handle the migration planning. This is what we used in this guide.

  • Versioned Workflow - Manage schema through sequential migration files with explicit version control. Ideal for production environments with strict change requirements.

For more detailed documentation, visit the provider registry page.