Terraform Basics: Your Complete Guide to Infrastructure as Code
📅 Published: August 2026
⏱️ Estimated Reading Time: 15 minutes
🏷️ Tags: Terraform, IaC, Infrastructure as Code, Beginner Guide, DevOps
Introduction: What is Terraform?
Terraform is an open-source Infrastructure as Code (IaC) tool created by HashiCorp. It lets you define and provision cloud infrastructure using a simple, declarative configuration language called HCL (HashiCorp Configuration Language).
Terraform in three sentences:
You write code that describes what infrastructure you want (servers, databases, networks). Terraform reads that code and figures out how to create it. Once created, Terraform tracks what it built so it can update or destroy it later.
Key features:
Declarative: You say what you want, not how to do it
Multi-cloud: Works with AWS, Azure, GCP, and 1,000+ providers
State management: Tracks what it created
Plan/Apply: Preview changes before applying them
Idempotent: Run the same code multiple times with consistent results
Part 1: Core Concepts
Infrastructure as Code
Terraform treats infrastructure like application code. You write it, version it, review it, and deploy it.
Infrastructure Code → Version Control → Review → Deploy → Infrastructure
The Workflow
The three essential commands:
terraform init # Prepare your working directory terraform plan # Preview what will change terraform apply # Make it happen
Providers
Providers are plugins that understand how to talk to cloud APIs.
# AWS provider provider "aws" { region = "us-west-2" } # Google Cloud provider provider "google" { project = "my-project" } # Kubernetes provider provider "kubernetes" { config_path = "~/.kube/config" }
Resources
Resources are the actual infrastructure components you create.
resource "aws_s3_bucket" "my_bucket" { bucket = "my-unique-bucket-name" acl = "private" }
Part 2: The Terraform Workflow
Step 1: Write Configuration
Create a file called main.tf:
# main.tf - Your first Terraform configuration terraform { required_version = ">= 1.5.0" required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } } provider "aws" { region = "us-east-1" } # Create an S3 bucket resource "aws_s3_bucket" "first_bucket" { bucket = "my-first-terraform-bucket-12345" tags = { Name = "My First Terraform Bucket" Environment = "Learning" ManagedBy = "Terraform" } } # Output the bucket name output "bucket_name" { value = aws_s3_bucket.first_bucket.bucket }
Step 2: Initialize
terraform init
This downloads the AWS provider and sets up your working directory.
Step 3: Plan
terraform plan
This shows you exactly what Terraform will do before it does anything.
Terraform will perform the following actions:
# aws_s3_bucket.first_bucket will be created
+ resource "aws_s3_bucket" "first_bucket" {
+ bucket = "my-first-terraform-bucket-12345"
+ tags = {
+ "Environment" = "Learning"
+ "ManagedBy" = "Terraform"
+ "Name" = "My First Terraform Bucket"
}
}
Plan: 1 to add, 0 to change, 0 to destroy.Step 4: Apply
terraform apply
Type yes when prompted. Your infrastructure is created!
Apply complete! Resources: 1 added, 0 changed, 0 destroyed. Outputs: bucket_name = "my-first-terraform-bucket-12345"
Step 5: Destroy (Clean Up)
terraform destroy
Type yes to delete everything.
Part 3: Variables and Outputs
Input Variables
Variables make your configuration reusable.
# variables.tf variable "environment" { description = "Deployment environment" type = string default = "dev" } variable "bucket_name" { description = "Name of the S3 bucket" type = string # No default = required } variable "tags" { description = "Resource tags" type = map(string) default = { ManagedBy = "Terraform" } } # Using variables resource "aws_s3_bucket" "main" { bucket = "${var.bucket_name}-${var.environment}" tags = var.tags }
Setting Variable Values
# Command line terraform apply -var="bucket_name=myapp" # Environment variable export TF_VAR_bucket_name="myapp" # terraform.tfvars file bucket_name = "myapp" environment = "prod"
Output Values
Outputs expose information after apply.
# outputs.tf output "bucket_arn" { description = "ARN of the bucket" value = aws_s3_bucket.main.arn } output "bucket_url" { description = "Bucket URL" value = "https://${aws_s3_bucket.main.bucket}.s3.amazonaws.com" }
terraform output terraform output bucket_arn
Part 4: State Management
What is State?
State is Terraform's memory. It maps your configuration to real infrastructure.
// terraform.tfstate (simplified) { "resources": [ { "type": "aws_s3_bucket", "name": "main", "instances": [{ "attributes": { "id": "myapp-dev-12345", "arn": "arn:aws:s3:::myapp-dev-12345" } }] } ] }
Local State (For Learning)
By default, state is stored in terraform.tfstate in your current directory.
terraform apply
# Creates terraform.tfstateRemote State (For Teams)
For teams, use remote state.
# backend.tf terraform { backend "s3" { bucket = "my-terraform-state" key = "prod/terraform.tfstate" region = "us-east-1" dynamodb_table = "terraform-locks" encrypt = true } }
State Commands
terraform state list # List all resources terraform state show aws_s3_bucket.main # Show resource details terraform state mv old_name new_name # Rename resource in state terraform state rm aws_s3_bucket.old # Remove from state
Part 5: Resources and Data Sources
Creating Resources
Resources are the building blocks of Terraform.
# AWS VPC resource "aws_vpc" "main" { cidr_block = "10.0.0.0/16" tags = { Name = "main-vpc" } } # AWS Subnet resource "aws_subnet" "public" { vpc_id = aws_vpc.main.id cidr_block = "10.0.1.0/24" tags = { Name = "public-subnet" } } # AWS Instance resource "aws_instance" "web" { ami = "ami-0c55b159cbfafe1f0" instance_type = "t2.micro" subnet_id = aws_subnet.public.id tags = { Name = "web-server" } }
Data Sources (Read-Only)
Data sources read information without creating anything.
# Get latest Ubuntu AMI data "aws_ami" "ubuntu" { most_recent = true owners = ["099720109477"] filter { name = "name" values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"] } } # Use it resource "aws_instance" "web" { ami = data.aws_ami.ubuntu.id instance_type = "t2.micro" } # Get existing VPC data "aws_vpc" "existing" { filter { name = "tag:Name" values = ["production-vpc"] } }
Part 6: Common Commands
| Command | Purpose |
|---|---|
terraform init | Initialize the working directory |
terraform plan | Preview changes |
terraform apply | Apply changes |
terraform destroy | Delete all resources |
terraform fmt | Format code consistently |
terraform validate | Check syntax |
terraform state list | List resources in state |
terraform state show | Show resource details |
terraform output | Show output values |
terraform refresh | Update state with real infrastructure |
Part 7: Getting Started Checklist
Setup
- □
Install Terraform
- □
Configure cloud provider credentials
- □
Choose a cloud provider (AWS, Azure, GCP)
First Configuration
- □
Write
main.tfwith provider block - □
Add a simple resource (like an S3 bucket)
- □
Run
terraform init - □
Run
terraform plan - □
Run
terraform apply
Good Practices
- □
Use variables for environment-specific values
- □
Use outputs to expose useful information
- □
Store state remotely for teams
- □
Never commit secrets to your Terraform files
- □
Run
terraform fmtbefore committing - □
Use modules for reusable components
Part 8: Common Patterns
Environment Separation
Using workspaces (simple):
terraform workspace new dev
terraform workspace new prod
terraform workspace select prodresource "aws_s3_bucket" "main" { bucket = "myapp-${terraform.workspace}" }
Using directories (more flexible):
environments/
├── dev/
│ ├── main.tf
│ └── terraform.tfvars
├── staging/
│ ├── main.tf
│ └── terraform.tfvars
└── prod/
├── main.tf
└── terraform.tfvars
modules/
└── s3-bucket/
├── main.tf
├── variables.tf
└── outputs.tfConditional Resources
# Create only if condition is true resource "aws_instance" "bastion" { count = var.enable_bastion ? 1 : 0 ami = "ami-0c55b159cbfafe1f0" instance_type = "t2.micro" }
Loops with Count
# Create 3 subnets resource "aws_subnet" "public" { count = 3 vpc_id = aws_vpc.main.id cidr_block = "10.0.${count.index}.0/24" tags = { Name = "public-subnet-${count.index + 1}" } }
Summary
The Three Terraform Rules:
Write: Define your infrastructure in
.tffilesPlan: Preview changes with
terraform planApply: Execute changes with
terraform apply
The Terraform Ecosystem:
| Component | Purpose |
|---|---|
| Providers | Connect to cloud APIs |
| Resources | Create infrastructure |
| Variables | Make configurable |
| Outputs | Expose information |
| State | Track what exists |
| Modules | Reusable components |
Learn More
Practice Terraform with hands-on exercises in our interactive labs:
https://devops.trainwithsky.com
Comments
Post a Comment