Terraform CLI
Introduction
The Terraform Command Line Interface (CLI) is your primary interface for working with Terraform configurations. It provides a consistent workflow for managing infrastructure across various providers such as AWS, Azure, Google Cloud, and many others. Whether you're creating new resources, modifying existing ones, or destroying infrastructure, the Terraform CLI is your go-to tool that translates your declarative configuration files into actual infrastructure changes.
In this guide, we'll explore the most important Terraform CLI commands that you'll use in your day-to-day infrastructure management, understand their purpose, and see how they fit into the Terraform workflow.
Installing the Terraform CLI
Before diving into the commands, let's make sure you have Terraform installed:
For macOS (using Homebrew):
brew install terraform
For Windows (using Chocolatey):
choco install terraform
For Linux:
wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt-get update && sudo apt-get install terraform
Verify your installation:
terraform -version
The Terraform Workflow
The core Terraform workflow consists of three main steps:
Let's explore the commands that correspond to each step in this workflow.
Key Terraform CLI Commands
terraform init
The terraform init
command initializes a working directory containing Terraform configuration files. It's the first command you should run after writing a new Terraform configuration or cloning an existing one.
What this command does:
- Downloads and installs providers defined in your configuration
- Initializes the backend where Terraform will store its state
- Downloads and installs modules referenced in your configuration
Example:
$ terraform init
Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 4.0"...
- Installing hashicorp/aws v4.67.0...
- Installed hashicorp/aws v4.67.0 (signed by HashiCorp)
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.
terraform fmt
The terraform fmt
command automatically updates configurations in the current directory for readability and consistency. It's a good practice to run this command before committing your code.
Example:
Before formatting:
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = "example-instance"
}
}
Command:
$ terraform fmt
After formatting:
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = "example-instance"
}
}
terraform validate
The terraform validate
command checks whether a configuration is syntactically valid and internally consistent. It's a good idea to run this after writing or making changes to your configuration.
Example:
$ terraform validate
Success! The configuration is valid.
If there are errors:
$ terraform validate
Error: Missing required argument
The argument "region" is required, but no definition was found.
terraform plan
The terraform plan
command creates an execution plan, showing what actions Terraform will take to change real infrastructure to match your configuration. This is a "dry run" and doesn't make any changes.
Example:
$ terraform plan
Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_instance.example will be created
+ resource "aws_instance" "example" {
+ ami = "ami-0c55b159cbfafe1f0"
+ instance_type = "t2.micro"
+ tags = {
+ "Name" = "example-instance"
}
# (other attributes omitted for brevity)
}
Plan: 1 to add, 0 to change, 0 to destroy.
You can save the plan to a file for later use:
$ terraform plan -out=tfplan
terraform apply
The terraform apply
command executes the actions proposed in a Terraform plan. It's used to create, update, or destroy infrastructure.
Example:
$ terraform apply
Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_instance.example will be created
+ resource "aws_instance" "example" {
+ ami = "ami-0c55b159cbfafe1f0"
+ instance_type = "t2.micro"
+ tags = {
+ "Name" = "example-instance"
}
# (other attributes omitted for brevity)
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to confirm.
Enter a value: yes
aws_instance.example: Creating...
aws_instance.example: Creation complete after 42s [id=i-1234567890abcdef0]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
If you've saved a plan, you can apply it directly:
$ terraform apply tfplan
terraform destroy
The terraform destroy
command destroys all resources managed by your Terraform configuration. It's like terraform apply
but specifically plans a destroy operation.
Example:
$ terraform destroy
Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
# aws_instance.example will be destroyed
- resource "aws_instance" "example" {
- ami = "ami-0c55b159cbfafe1f0" -> null
- instance_type = "t2.micro" -> null
- tags = {
- "Name" = "example-instance"
} -> null
# (other attributes omitted for brevity)
}
Plan: 0 to add, 0 to change, 1 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to confirm.
Enter a value: yes
aws_instance.example: Destroying...
aws_instance.example: Destruction complete after 32s
Destroy complete! Resources: 1 destroyed.
terraform state
The terraform state
command is used to manage the Terraform state file. It has several subcommands:
terraform state list
Lists all resources in the state:
$ terraform state list
aws_instance.example
aws_s3_bucket.data
terraform state show
Shows the attributes of a specific resource:
$ terraform state show aws_instance.example
# aws_instance.example:
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
"Name" = "example-instance"
}
# (other attributes omitted for brevity)
}
terraform state mv
Moves an item in the state, which is useful when you want to rename a resource:
$ terraform state mv aws_instance.example aws_instance.production
Move "aws_instance.example" to "aws_instance.production"
Successfully moved 1 object(s).
terraform state rm
Removes items from the state, which is useful when you want to manage a resource outside of Terraform:
$ terraform state rm aws_instance.example
Removed aws_instance.example
Successfully removed 1 resource instance(s).
terraform output
The terraform output
command is used to extract the values of output variables from the state file.
Example:
If your configuration has outputs defined:
output "instance_ip" {
value = aws_instance.example.public_ip
}
output "instance_id" {
value = aws_instance.example.id
}
You can view all outputs:
$ terraform output
instance_id = "i-1234567890abcdef0"
instance_ip = "203.0.113.10"
Or a specific output:
$ terraform output instance_ip
"203.0.113.10"
terraform import
The terraform import
command imports existing infrastructure into your Terraform state. This is useful when you want to bring existing resources under Terraform management.
Example:
$ terraform import aws_instance.example i-1234567890abcdef0
aws_instance.example: Importing from ID "i-1234567890abcdef0"...
aws_instance.example: Import prepared!
Prepared aws_instance for import
aws_instance.example: Refreshing state... [id=i-1234567890abcdef0]
Import successful!
The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.
terraform workspace
Terraform workspaces allow you to manage multiple states within a single directory. This is useful for managing different environments (development, staging, production) with the same configuration.
terraform workspace list
Lists all workspaces:
$ terraform workspace list
* default
development
production
terraform workspace new
Creates a new workspace:
$ terraform workspace new staging
Created and switched to workspace "staging"!
You're now on a new, empty workspace. Workspaces isolate their state,
so if you run "terraform plan" Terraform will not see any existing state
for this configuration.
terraform workspace select
Switches to another workspace:
$ terraform workspace select production
Switched to workspace "production".
Real-World Example: Creating a Web Server on AWS
Let's see a complete example of using the Terraform CLI to create an AWS EC2 instance that serves as a web server.
Step 1: Create the Configuration Files
Create a file named main.tf
:
provider "aws" {
region = "us-west-2"
}
resource "aws_instance" "web_server" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
user_data = <<-EOF
#!/bin/bash
echo "Hello, World!" > index.html
nohup python -m SimpleHTTPServer 80 &
EOF
tags = {
Name = "terraform-example-web-server"
}
}
output "public_ip" {
value = aws_instance.web_server.public_ip
}
Step 2: Initialize the Directory
$ terraform init
Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 4.0"...
- Installing hashicorp/aws v4.67.0...
- Installed hashicorp/aws v4.67.0 (signed by HashiCorp)
Terraform has been successfully initialized!
Step 3: Format and Validate the Configuration
$ terraform fmt
$ terraform validate
Success! The configuration is valid.
Step 4: Plan the Changes
$ terraform plan
Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_instance.web_server will be created
+ resource "aws_instance" "web_server" {
+ ami = "ami-0c55b159cbfafe1f0"
+ instance_type = "t2.micro"
+ user_data = "#!/bin/bash
echo \"Hello, World!\" > index.html
nohup python -m SimpleHTTPServer 80 &
"
+ tags = {
+ "Name" = "terraform-example-web-server"
}
# (other attributes omitted for brevity)
}
Plan: 1 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ public_ip = (known after apply)
Step 5: Apply the Changes
$ terraform apply
# Same output as plan, followed by:
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to confirm.
Enter a value: yes
aws_instance.web_server: Creating...
aws_instance.web_server: Creation complete after 45s [id=i-0abc123def456789]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Outputs:
public_ip = "203.0.113.10"
Step 6: Access the Web Server
You can now access your web server by visiting the IP address in your browser:
$ curl http://203.0.113.10
Hello, World!
Step 7: Destroy the Infrastructure
When you're done experimenting:
$ terraform destroy
# Output showing planned destruction...
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to confirm.
Enter a value: yes
aws_instance.web_server: Destroying...
aws_instance.web_server: Destruction complete after 35s
Destroy complete! Resources: 1 destroyed.
Common Command Options
Many Terraform commands support additional options:
-auto-approve
Skips interactive approval of plan. Use with caution!
$ terraform apply -auto-approve
$ terraform destroy -auto-approve
-var
Sets a value for an input variable:
$ terraform apply -var="instance_type=t2.micro"
-var-file
Specifies a file containing variable values:
$ terraform apply -var-file="prod.tfvars"
-target
Limits operations to only the specified resource:
$ terraform apply -target=aws_instance.example
Troubleshooting Tips
1. Debug Logs
Enable detailed logs for troubleshooting:
$ export TF_LOG=DEBUG
$ terraform apply
# Very verbose output
Log levels: TRACE, DEBUG, INFO, WARN, ERROR
2. State Lock Issues
If Terraform can't acquire a state lock:
$ terraform force-unlock LOCK_ID
3. Provider Plugin Issues
If you have issues with providers:
$ rm -rf .terraform/
$ terraform init
Best Practices
- Version Control: Always store your Terraform configurations in version control.
- Format Before Commit: Run
terraform fmt
before committing your code. - Validate Regularly: Run
terraform validate
to catch syntax errors early. - Always Plan: Always run
terraform plan
before applying changes. - Use Workspaces: Use workspaces to manage
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)