The Problem with ClickOps
Manually provisioning resources through a cloud console is fast for one-offs but doesn't scale, can't be reviewed, and can't be reliably reproduced. Infrastructure as Code (IaC) solves this by treating your infrastructure the same way you treat application code — versioned, reviewable, and repeatable.
Terraform Basics
Terraform uses HCL (HashiCorp Configuration Language) to describe resources. You define what you want, and Terraform figures out how to create, update, or destroy resources to match that desired state.
# main.tf — a basic AWS VPC and subnet
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
tags = { Name = "main-vpc" }
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "us-east-1a"
tags = { Name = "public-subnet" }
}The Core Workflow
Every Terraform workflow follows the same three steps: terraform init (download providers), terraform plan (preview changes), terraform apply (execute changes). Never skip the plan step in production.
terraform init
terraform plan -out=tfplan
terraform apply tfplanManaging State
Terraform tracks deployed resources in a state file. In a team environment, store state remotely in an S3 bucket with DynamoDB locking — never commit state files to git, as they often contain sensitive values.
# backend.tf — remote state in S3
terraform {
backend "s3" {
bucket = "my-tf-state-bucket"
key = "infra/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "tf-state-lock"
encrypt = true
}
}Where to Go Next
Once you're comfortable with the basics, explore modules (reusable resource groupings), workspaces (environment separation), and Terragrunt for DRY multi-environment configurations. The Terraform Registry has community modules for nearly every common AWS, Azure, and GCP pattern.
