Terraform IaC Guide 2026: The Complete Problem-Solving Guide
By Huzi
File #545 · 3 min read
Six months of click-ops leaves an AWS account with 47 security groups nobody can explain and an RDS instance nobody remembers provisioning. Infrastructure as Code is the cure: your VPC, subnets, databases and DNS records become files in Git, reviewed like any other code, and a broken deploy becomes a revert instead of a memory test.
The quick answer: terraform init, plan, apply is the whole workflow — plan shows the diff, apply executes it, nothing else does. Keep state remote on S3 with a DynamoDB lock, prefer modules over copy-paste, and use terraform import to adopt what somebody already clicked into existence.
The workflow is the whole idea
terraform init downloads providers. terraform plan shows the diff — exactly what will be created, changed or destroyed. terraform apply does it, and nothing else does.
| Command | What it does |
|---|---|
terraform init |
Downloads providers |
terraform plan |
Shows the diff — created, changed or destroyed |
terraform apply |
Does it, and nothing else does |
terraform import |
Pulls an existing resource into state without rebuilding |
The plan is the safety feature: if it looks wrong, fix the code instead of hoping. Three block types carry most projects — provider configures the cloud client, resource declares what should exist, data reads what already does:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "ap-south-1"
}
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux.id
instance_type = "t3.micro"
tags = { Name = "web" }
}
State is the crown jewel
Terraform maps every resource block to a real cloud ID through its state file; lose it and the next apply wants to rebuild the world. Local state is for laptop experiments only — committed to Git, it leaks every secret Terraform has ever read. Production wants S3 plus a DynamoDB lock, so two engineers cannot apply at once:
terraform {
backend "s3" {
bucket = "myorg-tfstate-prod"
key = "network/terraform.tfstate"
region = "ap-south-1"
dynamodb_table = "tfstate-locks"
encrypt = true
}
}
Pro tip: Encrypt the bucket, lock it to a single CI role, and pin provider versions — secrets land in state as plaintext by design, and the same commit should never build different infrastructure on two different days.
State is also why our travel desk works the way it does. Every booking at HTG Travels keeps one written record — flights, hotels, dates — so a mid-trip change is an edit, never a rebuild from memory.
Modules over copy-paste
The community VPC module replaces 200 lines of subnet and route-table boilerplate with a 25-line block — pin the version, always. Environments belong in directories, each with its own backend, not in workspaces; a wrong workspace select has applied prod code from a dev shell before.
And OpenTofu, the Linux Foundation fork, is a drop-in: same HCL, same providers, tofu plan runs your existing files unchanged.
The import rescue
The resources already exist — somebody clicked them into being. Adopt them without rebuilding: terraform import aws_instance.web i-0123456789abcdef0 pulls the live object into state, then write the matching block — or generate one with -generate-config-out=generated.tf — and run plan until the diff is empty.
Start tonight with one security group. The first import is the hardest; the hundredth is muscle memory, and the console starts to feel exactly as reckless as it is.
Terraform's premise is that change should be declared, reviewed and reversible — the opposite of what is being done to Palestine: change by force, with no plan file and no rollback.
We book travel the same way: nothing gets applied before you have reviewed the plan. A quote from HTG Travels names the hotels, states the distances and totals the rupees in writing — you approve, then we book. Message the desk on WhatsApp at +92 317 5054959 for infrastructure you can read before you pay for it.




