Terraform From Zero to Advanced: A Beginner-Friendly Guide

🚀 𝐀𝐛𝐨𝐮𝐭 𝐌𝐞 "Hi, I'm Ali masiu zama, a DevOps student passionate about cloud computing and automation. I'm currently learning AWS, Linux, Docker, and CI/CD pipelines, with a focus on automating workflows and building scalable solutions.
Introduction
Terraform is one of the most powerful tools for Infrastructure as Code (IaC). It allows you to create, change, and manage cloud resources using simple configuration files. Whether you're deploying an EC2 instance, an S3 bucket, or an entire VPC, Terraform makes everything repeatable, automated, and error‑free.
This guide will walk you through Terraform from absolute basics to advanced concepts in the simplest possible way.
Table of Contents
What is Terraform?
Why Terraform?
How Terraform Works
Terraform Architecture
Providers
Arguments & Meta‑Arguments
Modules
Remote Backends
Workspaces
Terraform Lifecycle
Provisioners
Data Sources
Common Terraform Commands
Terraform Code – Create an EC2 Instance
Terraform Code – Create an S3 Bucket
Terraform Code – Create a VPC, Subnet, IGW, Route Table (Basic Setup)
Conclusion
1. What is Terraform?
Terraform is an Infrastructure as Code tool that lets you define cloud resources (AWS, Azure, GCP, etc.) in .tf files using simple syntax. Instead of clicking buttons in the console, you write code.
Terraform reads this configuration and creates the infrastructure exactly as described.
2. Why Terraform?
Automation: No manual setup.
Consistency: Same setup everywhere.
Multi‑Cloud: Supports almost all cloud platforms.
Version Control: You can track changes in Git.
Reusable: Write once, reuse multiple times with modules.
3. How Terraform Works
Terraform follows a simple workflow:
Write (.tf files)
Initialize (
terraform init)Validate (
terraform validate)Plan (
terraform plan)Apply (
terraform apply)Destroy (
terraform destroy)
Terraform takes your desired state (what you wrote) and matches it with actual state (what exists), then applies changes.
4. Terraform Architecture
Terraform is made of:

| Components | Purpose (Explanation) |
| Core Engine | Reads your .tf files, compares desired vs. actual state, and creates an execution plan. |
| Providers | Plugins that allow Terraform to interact with cloud/platform APIs (AWS, Azure, GCP, GitHub, Kubernetes, etc.). |
| State File | Stores information about real resources so Terraform knows what already exists and what needs changes. |
| Backend | Determines where the state file is stored (local machine, S3 bucket, Terraform Cloud, etc.). |
Install Terraform (Linux – Ubuntu/Debian)
sudo apt update
sudo apt install -y gnupg software-properties-common
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 -y terraform
Check version:
terraform -version
5. Providers
- Providers are plugins that teach Terraform how to talk to a cloud or service.
It knows how to create, update, delete, and manage resources for a specific platform.

Example providers include:
AWS
Azure
Google Cloud
GitHub
Kubernetes
Docker
Each provider contains the logic + API calls needed to manage resources.
Why Terraform Needs Providers?
Terraform itself does NOT know how to:
create an EC2 instance
create an S3 bucket
create a VPC
update an IAM policy
All of this knowledge comes from the provider plugin.
So Terraform acts like the “brain,”
and the provider is the “hands” that perform the actual API calls.
Example:
provider "aws" {
region = "us-west-2"
access_key = "my-access-key"
secret_key = "my-secret-key"
}
Terraform automatically downloads providers during terraform init.
Terraform provider Documentation say
Providers are the bridge between Terraform and the actual service API.
Providers support resources (things you create or manage).
Providers support data sources (things you read from the cloud).
Providers can be configured once or multiple times.
Providers are downloaded via
terraform init.
6. Arguments & Meta‑Arguments
Arguments
Regular properties inside a resource.
Example:
ami = "ami-123456"
instance_type = "t2.micro"
Meta‑Arguments
Special features Terraform gives you:
countfor_eachdepends_on
count
Used to create multiple copies of the same resource.
Uses a number (0, 1, 2, …).
Good for conditional creation (
count = 0= don’t create).
Example:
count = 2
Creates 2 resources.
for_each (Create multiple resources using names/keys)
for_each is used when you want to create multiple resources, and each item has its own identity (name, key, tag, etc.).
Why use for_each?
Creates resources based on a map or set
Gives stable names (unlike
count, where indexes can shift)Best when each resource has a unique key
Example
resource "aws_instance" "servers" {
for_each = {
dev = "t2.micro"
prod = "t2.small"
}
instance_type = each.value
tags = {
Name = each.key
}
}
This creates 2 EC2 instances:
✔ One named dev
✔ One named prod
depends_on (Force resource ordering)
depends_on tells Terraform:
👉 "Create this only after another resource is done."
Terraform usually detects dependencies automatically, but sometimes you must force it.
Why use depends_on?
When Terraform cannot detect connection
When resources are logically connected but not referenced directly
Ensures proper ordering
Example
resource "aws_s3_bucket" "logs" {
bucket = "my-logs-bucket"
}
resource "aws_iam_role" "role" {
name = "logging-role"
depends_on = [aws_s3_bucket.logs] # Wait for bucket
}
The IAM role waits until the S3 bucket is created.
7. Modules (Reusable Terraform components)
Modules allow you to organize Terraform code and reuse it.

Why use modules?
Clean folder structure
Reusable templates
Production-ready design
Easier maintenance
Example: Module Folder Structure
modules/
ec2/
main.tf
variables.tf
outputs.tf
Calling the module
module "my_ec2" {
source = "./modules/ec2"
instance_type = "t2.micro"
}
Modules are like functions
You write code once → use many times.
9. Remote Backends
A backend is where Terraform stores the state file.
Remote backends make Terraform state:
Safe
Shareable
Locked (so two people cannot run Terraform at the same time)
Version-controlled
Most popular backend
➡️ AWS S3 + DynamoDB (for state locking)
Example Backend Configuration
terraform {
backend "s3" {
bucket = "mytfbucket"
key = "state/dev.tfstate"
region = "ap-south-1"
dynamodb_table = "tf-state-lock"
}
}
What this does:
Stores state in S3 bucket
Locks state using DynamoDB
Prevents two DevOps engineers from running
terraform applyat the same time
This is a must for production.
10. Workspaces
Workspaces let you run multiple environments (dev, stage, prod) using the same Terraform code.
Why workspaces?
You don’t need separate folders or duplicate files.
Example:
dev
stage
prod
Each workspace gets its own state file, like:
terraform.tfstate.d/dev/terraform.tfstate
terraform.tfstate.d/prod/terraform.tfstate
Commands:
terraform workspace new dev #Create a workspace
terraform workspace select dev #Switch workspace
terraform workspace list #List all workspaces
11. Terraform Lifecycle
Controls special behaviors of a resource.
It has 4 important sub-options:

1. Init (terraform init)
Downloads the required provider plugins and prepares the working directory.
2. Plan (terraform plan)
Shows what Terraform will create, update, or delete — a preview before making changes.
3. Apply (terraform apply)
Executes the plan and actually creates or updates the infrastructure.
4. Destroy (terraform destroy)
Deletes the infrastructure that Terraform created.
Example:
terraform init # Initialize
terraform plan # See what will happen
terraform apply # Create resources
terraform destroy # Destroy everything
12. Provisioners
Used to run scripts or commands after a resource is created.
Types:
local-exec→ run on your laptopremote-exec→ run on EC2 or serverfile→ copy files to server
Example:
provisioner "remote-exec" {
inline = ["sudo apt update"]
}
Use provisioners only when absolutely necessary.
13. Data Sources
Data sources help you fetch existing information.
Example:
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"]
}
14. Common Terraform Commands
terraform init # Initialize
terraform validate # Validate syntax
terraform plan # See what will happen
terraform apply # Create resources
terraform destroy # Destroy everything
terraform destroy -target=aws_s3_bucket.my_bucket # Destroy specific resource
terraform state list # Check all managed resources
15. Terraform Code – Create an EC2 Instance
Create a file: ec2.tf
provider "aws" {
region = "ap-south-1"
access_key = "my-access-key"
secret_key = "my-secret-key"
}
resource "aws_instance" "my_ec2" {
ami = "ami-0c2b8ca1dad447f8a" # (Ubuntu image)
instance_type = "t2.micro"
tags = {
Name = "my-ec2-instance" # Your server name which you will create.
}
}
Commands:
terraform init # Initialize
terraform validate # Validate syntax
terraform plan # See what will happen
terraform apply # Create resources
16. Terraform Code – Create an S3 Bucket
Create a file: s3.tf
provider "aws" {
region = "ap-south-1"
access_key = "my-access-key"
secret_key = "my-secret-key"
}
resource "aws_s3_bucket" "my_bucket" {
bucket = "ali-demo-bucket-12345" # bucket name must be unique globally
tags = {
Name = "My bucket"
Environment = "Dev" # It is a custom tag used to identify the environment in which this resource is used."
}
}
17. Terraform Code – Create a VPC, Subnet, IGW, Route Table (Basic Setup)
Create file: vpc.tf
# AWS Provider Configuration
provider "aws" {
region = "ap-south-1" # AWS region (Mumbai)
access_key = "my-access-key" # Your AWS access key
secret_key = "my-secret-key" # Your AWS secret key
}
resource "aws_vpc" "main_vpc" {
cidr_block = "10.0.0.0/16" # Main network range for VPC
tags = {
Name = "main-vpc" # Name tag for identification
}
}
resource "aws_subnet" "public_subnet" {
vpc_id = aws_vpc.main_vpc.id # Attach subnet to VPC
cidr_block = "10.0.1.0/24" # Subnet range
map_public_ip_on_launch = true # Auto-assign public IP
tags = {
Name = "public-subnet" # Tag for subnet
}
}
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main_vpc.id # Attach IGW to VPC
tags = {
Name = "main-igw" # Name tag
}
}
resource "aws_route_table" "public_rt" {
vpc_id = aws_vpc.main_vpc.id # Attach RT to VPC
route {
cidr_block = "0.0.0.0/0" # All traffic
gateway_id = aws_internet_gateway.igw.id # Send to IGW
}
tags = {
Name = "public-route-table" # Tag for route table
}
}
# Route Table Association
# Connect Subnet → Route Table
resource "aws_route_table_association" "public_rt_assoc" {
subnet_id = aws_subnet.public_subnet.id # Which subnet?
route_table_id = aws_route_table.public_rt.id # Which route table?
}
18. Conclusion
Terraform is simple but powerful. By mastering resources, variables, modules, state, backends, and advanced concepts, you can manage any cloud infrastructure with confidence.
Use this guide as your foundation and keep practicing by building real projects like VPCs, EC2 setups, multi-tier architectures, and automated modules.




