Getting Started with Terraform
Install Terraform and deploy your first infrastructure
Getting Started with Terraform
"Infrastructure as Code" sounds like something a consultant made up to charge more. But it's actually simple ā you write config files that describe what you want, and Terraform makes it happen. No clicking around in cloud consoles, no forgetting what you changed last Tuesday.
What is Terraform?
So what does Terraform actually do?
Think of it as a very obedient robot:
- You hand it a blueprint (config files) describing your infrastructure
- It figures out what needs to change
- It talks to your cloud provider and makes those changes
The key idea: you describe the end state ("I want 3 servers"), not the steps to get there. Terraform handles the how. It's like ordering food at a restaurant ā you say what you want, not how to cook it.
Install Terraform
macOS (Homebrew)
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
Linux (Ubuntu/Debian)
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /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 update && sudo apt install terraform
Windows
choco install terraform
Or download from terraform.io/downloads.
Verify Installation
Almost done? Not yet dude. Let's verify it actually installed:
terraform version
You should see something like Terraform v1.7.0. If you see that, you're golden!
Set Up AWS Credentials
"Wait, how does Terraform talk to AWS?"
Great question. Terraform needs permission to create resources ā it's not going to hack into your AWS account. You need to give it credentials:
Option 1: Environment Variables
export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"
export AWS_REGION="us-east-1"
Option 2: AWS CLI Profile
aws configure
This creates ~/.aws/credentials ā Terraform finds it automatically.
Option 3: IAM Role (on EC2/ECS)
If running on AWS, use IAM roles. No credentials to manage. This is the best option for production ā we'll talk more about this later.
Your First Terraform Config
Alright, enough setup. Let's actually build something! Create a new directory:
mkdir learn-terraform && cd learn-terraform
Create main.tf:
# Configure the AWS provider
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
# Create an S3 bucket
resource "aws_s3_bucket" "my_bucket" {
bucket = "my-first-terraform-bucket-12345" # Must be globally unique
tags = {
Name = "My First Bucket"
Environment = "Learning"
}
}
That's it. That's the whole config. This creates an S3 bucket in AWS. How cool is that?
The Terraform Workflow
Here's the thing ā you'll use these three commands 95% of the time. Memorize them:
1. terraform init
Initialize the working directory:
terraform init
Output:
Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 5.0"...
- Installing hashicorp/aws v5.31.0...
Terraform has been successfully initialized!
This downloads the AWS provider plugin. Think of it as npm install for Terraform ā run it once per project (or when you add new providers).
2. terraform plan
"Can I see what it's going to do before it actually does it?"
Yes! That's exactly what plan does ā it's a preview, a dry run:
terraform plan
Output:
Terraform will perform the following actions:
# aws_s3_bucket.my_bucket will be created
+ resource "aws_s3_bucket" "my_bucket" {
+ bucket = "my-first-terraform-bucket-12345"
+ id = (known after apply)
+ tags = {
+ "Environment" = "Learning"
+ "Name" = "My First Bucket"
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
The + means "will be created". Nothing has happened yet ā this is just a preview. Like looking at the receipt before you pay.
3. terraform apply
Time to make it real:
terraform apply
Terraform shows the plan again and asks for confirmation:
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
Type yes, hit Enter. Terraform creates the bucket.
aws_s3_bucket.my_bucket: Creating...
aws_s3_bucket.my_bucket: Creation complete after 2s [id=my-first-terraform-bucket-12345]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Boom! Check your AWS console ā the bucket exists! You just created cloud infrastructure with a text file. Let that sink in.
Making Changes
"What if I need to change something?"
Just update the config file. Terraform figures out the diff. Change the tag in main.tf:
tags = {
Name = "My First Bucket"
Environment = "Development" # Changed from "Learning"
}
Run terraform plan:
# aws_s3_bucket.my_bucket will be updated in-place
~ resource "aws_s3_bucket" "my_bucket" {
~ tags = {
~ "Environment" = "Learning" -> "Development"
# (1 unchanged element hidden)
}
}
Plan: 0 to add, 1 to change, 0 to destroy.
The ~ means "will be modified" ā not creating or destroying, just tweaking. Apply it:
terraform apply
Destroying Resources
Done playing around? Let's clean up so you don't get a surprise AWS bill:
terraform destroy
# aws_s3_bucket.my_bucket will be destroyed
- resource "aws_s3_bucket" "my_bucket" {
- bucket = "my-first-terraform-bucket-12345"
- tags = {
- "Environment" = "Development"
- "Name" = "My First Bucket"
}
}
Plan: 0 to add, 0 to change, 1 to destroy.
Do you really want to destroy all resources?
Type yes. Bucket gone. No more charges. Clean as a whistle.
What Just Happened?
Let's recap what actually happened behind the scenes:
- init ā Downloaded the AWS provider plugin
- plan ā Read your config, compared to current state, showed differences
- apply ā Made API calls to AWS to create/update resources
- destroy ā Made API calls to delete resources
Terraform also created a terraform.tfstate file. This tracks what resources exist ā it's Terraform's memory. We'll cover state management in detail later ā for now, just don't delete it. Seriously.
Project Files
After running, your directory looks like:
learn-terraform/
āāā main.tf # Your config
āāā terraform.tfstate # Current state (what exists)
āāā .terraform/ # Provider plugins
āāā .terraform.lock.hcl # Provider version lock
Add to .gitignore:
.terraform/
*.tfstate
*.tfstate.*
Don't commit state files ā they may contain secrets (passwords, API keys, the works). We'll cover remote state later.
Quick Reference
| Command | What it does |
|---|---|
terraform init | Initialize, download providers |
terraform plan | Preview changes |
terraform apply | Apply changes |
terraform destroy | Delete everything |
terraform fmt | Format code nicely |
terraform validate | Check syntax |
Common Mistakes
You will hit these. Everyone does.
Bucket name not unique
Error: creating S3 Bucket: BucketAlreadyExists
S3 bucket names are globally unique across all AWS accounts worldwide. Add random characters or your name to make it unique.
Wrong region
Resources created in unexpected region? Check your provider block or AWS_REGION env var.
No credentials
Error: No valid credential sources found
Set up AWS credentials (see above).
What's Next?
Look at you ā you just went from zero to creating cloud infrastructure with a text file. You now know:
- The init ā plan ā apply workflow (your new best friend)
- How to read plan output (
+create,~modify,-destroy) - How to clean up with
destroy
But main.tf was pretty basic. Time to learn HCL syntax and resources properly ā things get a lot more interesting from here. Let's go!