Infrastructure as Code with Terraform: From Zero to Production
Terraform by HashiCorp lets you define cloud infrastructure in declarative configuration files. You describe your desired state and Terraform figures out how to get there.
Why Infrastructure as Code?
- Reproducibility — spin up identical environments in minutes
- Version control — review infra changes in pull requests
- Automation — no more clicking through cloud consoles
- Documentation — your code is your documentation
Installing Terraform
# macOS
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
# Verify
terraform version
Your First Configuration
Create a main.tf file:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
}
variable "aws_region" {
default = "us-east-1"
}
resource "aws_s3_bucket" "app_assets" {
bucket = "my-app-assets-${random_id.suffix.hex}"
tags = {
Environment = "production"
ManagedBy = "terraform"
}
}
resource "random_id" "suffix" {
byte_length = 4
}
output "bucket_name" {
value = aws_s3_bucket.app_assets.bucket
}
Core Workflow
# Initialize — downloads provider plugins
terraform init
# Plan — preview what will change
terraform plan
# Apply — create/update resources
terraform apply
# Destroy — tear everything down
terraform destroy
State Management
Terraform tracks resources in a state file. For teams, store state remotely:
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
Modules
Organize reusable infrastructure into modules:
modules/
vpc/
main.tf
variables.tf
outputs.tf
ecs/
main.tf
variables.tf
outputs.tf
Reference them:
module "vpc" {
source = "./modules/vpc"
cidr = "10.0.0.0/16"
}
module "ecs" {
source = "./modules/ecs"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnet_ids
}
Best Practices
- Never commit state files — add
*.tfstate*to.gitignore - Use workspaces or separate state files per environment
- Pin provider versions to avoid breaking changes
- Run
terraform planin CI on every pull request - Use
terraform fmtandterraform validateas pre-commit hooks - Tag every resource with
ManagedBy = "terraform"
Common Gotchas
- Deleting resources from config doesn't destroy them until you run
apply - Renaming a resource destroys the old one and creates a new one — use
movedblocks - Always use
-auto-approveonly in automated pipelines, never interactively
Terraform pairs beautifully with CI/CD pipelines. Add a plan step on PRs and an apply step on merge to main for fully automated infrastructure.
Tagged with
Enjoyed this article?
Get more DevOps insights delivered to your inbox.
Get new posts by email
Subscribe to get an email when a new blog post is published. Skip anytime.
No spam, unsubscribe anytime.
Discussion
0 comments
Sign in to join the conversation.
Be the first to comment
Start a conversation about this post
