Infrastructure as Code transforms “click around the AWS console” into version-controlled, reviewable, repeatable deployments. Terraform is the most widely used IaC tool — it manages AWS, GCP, Azure, and hundreds of other providers with the same language. This guide takes you from first terraform init to production-grade module patterns used in real teams.
⚡ TL;DR: Write .tf files declaring desired state. terraform plan shows what will change. terraform apply makes it so. State file tracks what Terraform manages. Modules are reusable infrastructure components. Remote state (S3 + DynamoDB) enables team collaboration. Import existing resources.
Core concepts: resources, variables, outputs
# main.tf — define an EC2 instance
provider "aws" {
region = var.aws_region
}
variable "aws_region" {
description = "AWS region"
default = "us-east-1"
type = string
}
variable "instance_type" {
description = "EC2 instance type"
type = string
validation {
condition = contains(["t3.micro", "t3.small", "t3.medium"], var.instance_type)
error_message = "Must be a valid t3 instance type."
}
}
resource "aws_instance" "api_server" {
ami = data.aws_ami.amazon_linux.id
instance_type = var.instance_type
vpc_security_group_ids = [aws_security_group.api.id]
tags = {
Name = "api-server"
Environment = var.environment
ManagedBy = "terraform"
}
}
output "api_server_ip" {
description = "Public IP of API server"
value = aws_instance.api_server.public_ip
}
Remote state — essential for teams
# Remote state: store state in S3, lock with DynamoDB
# terraform/backend.tf
terraform {
backend "s3" {
bucket = "mycompany-terraform-state"
key = "prod/api/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-state-lock" # Prevent concurrent applies
}
}
# Create the state bucket and lock table (do this manually first):
resource "aws_s3_bucket" "tfstate" {
bucket = "mycompany-terraform-state"
}
resource "aws_s3_bucket_versioning" "tfstate" {
bucket = aws_s3_bucket.tfstate.id
versioning_configuration { status = "Enabled" }
}
resource "aws_dynamodb_table" "tfstate_lock" {
name = "terraform-state-lock"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute { name = "LockID"; type = "S" }
}
Modules — reusable infrastructure
# modules/ec2-service/main.tf
variable "name" {} variable "instance_type" {}
variable "vpc_id" {} variable "subnet_ids" { type = list(string) }
resource "aws_security_group" "this" {
name = "${var.name}-sg"
vpc_id = var.vpc_id
ingress { from_port = 443; to_port = 443; protocol = "tcp"; cidr_blocks = ["0.0.0.0/0"] }
egress { from_port = 0; to_port = 0; protocol = "-1"; cidr_blocks = ["0.0.0.0/0"] }
}
resource "aws_instance" "this" {
ami = data.aws_ami.amazon_linux.id
instance_type = var.instance_type
subnet_id = var.subnet_ids[0]
vpc_security_group_ids = [aws_security_group.this.id]
}
output "instance_id" { value = aws_instance.this.id }
# Use the module:
module "api" {
source = "./modules/ec2-service"
name = "api"
instance_type = "t3.medium"
vpc_id = aws_vpc.main.id
subnet_ids = aws_subnet.private[*].id
}
Essential Terraform commands
# Workflow:
terraform init # Download providers, configure backend
terraform fmt -recursive # Format all .tf files
terraform validate # Check syntax and types
terraform plan # Preview changes (safe, no changes made)
terraform apply # Apply changes (prompts for confirmation)
terraform apply -auto-approve # CI: skip confirmation
terraform destroy # Destroy all resources (CAREFUL!)
# State management:
terraform state list # List all managed resources
terraform state show aws_instance.api # Show resource details
terraform import aws_instance.api i-1234567890abcdef0 # Import existing
terraform taint aws_instance.api # Mark for recreation on next apply
- ✅ Always terraform plan before apply — review every change
- ✅ Remote state in S3 + DynamoDB for team collaboration
- ✅ Modules for reusable patterns (VPC, EC2 cluster, RDS)
- ✅ Variables with validation blocks — catch errors before apply
- ✅ Tag every resource with Name, Environment, ManagedBy=terraform
- ❌ Never edit state file manually — use terraform state commands
- ❌ Never store secrets in .tf files — use AWS Secrets Manager or SSM
Terraform manages the infrastructure that hosts your Lambda functions and data lake architecture. External reference: Terraform documentation.
Recommended Reading
→ Designing Data-Intensive Applications — The essential book every senior developer needs.
→ The Pragmatic Programmer — Timeless engineering wisdom for writing better code.
Affiliate links. We earn a small commission at no extra cost to you.
Free Weekly Newsletter
🚀 Don’t Miss the Next Cheat Code
Join 1,000+ senior developers getting expert JS, Python, AWS and system design secrets weekly.
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.
