Table of Contents
What is Infrastructure as Code?
Infrastructure as Code (IaC) means defining your cloud infrastructure in configuration files instead of clicking through AWS Console. Your entire infrastructure — servers, databases, networking, IAM roles — is described in code that can be version-controlled, reviewed, and reproduced.
The benefits are massive: - Reproducibility: Spin up identical environments in minutes - Version Control: Track every infrastructure change in git - Code Review: Review infrastructure changes like code changes - Disaster Recovery: Recreate your entire stack from config files
Why Terraform?
While AWS has CloudFormation and each cloud has its own IaC tool, Terraform stands apart:
- Multi-cloud: One language (HCL) works with AWS, Azure, GCP, and 3000+ providers - State Management: Terraform tracks what exists vs. what's defined, making updates safe - Plan Before Apply: terraform plan shows exactly what will change before you commit - Modular: Build reusable modules for common patterns (VPC, ECS cluster, Lambda stack) - Community: Terraform Registry has thousands of pre-built modules
Core Concepts
Terraform has four fundamental concepts:
1. Providers — Plugins that connect to cloud APIs (AWS, Azure, GCP, etc.) 2. Resources — Individual infrastructure components (aws_lambda_function, aws_dynamodb_table) 3. State — A JSON file tracking what Terraform manages and current resource attributes 4. Modules — Reusable packages of resources (your own VPC module, community modules from Registry)
# main.tf — Example AWS Lambda + DynamoDB
terraform {
required_providers {
aws = { source = "hashicorp/aws", version = "~> 5.0" }
}
}
provider "aws" { region = "eu-central-1" }
resource "aws_dynamodb_table" "main" {
name = "my-app-table"
billing_mode = "PAY_PER_REQUEST"
hash_key = "PK"
range_key = "SK"
attribute {
name = "PK"
type = "S"
}
attribute {
name = "SK"
type = "S"
}
}
resource "aws_lambda_function" "api" {
function_name = "my-app-api"
runtime = "nodejs20.x"
handler = "index.handler"
filename = "lambda.zip"
role = aws_iam_role.lambda.arn
environment {
variables = {
TABLE_NAME = aws_dynamodb_table.main.name
}
}
}The Terraform Workflow
Every Terraform change follows the same safe workflow:
1. terraform init — Download providers and initialize backend 2. terraform plan — Preview changes (what will be created, updated, or destroyed) 3. terraform apply — Execute the plan after your confirmation 4. terraform destroy — Tear down everything when no longer needed
The plan step is critical — it shows you exactly what will happen before any changes are made. In production, run plan in CI and require approval before apply.
Real-World: My AWS Stack
For my serverless applications, I use Terraform to manage:
- DynamoDB tables with on-demand billing - Lambda functions with proper IAM roles (least privilege) - API Gateway with custom domains and SSL certificates - S3 buckets for static hosting with CloudFront distributions - SQS queues with dead letter queues - CloudWatch alarms and log groups
The entire stack is defined in ~300 lines of HCL. Spinning up a new environment takes one command: terraform apply -var="env=staging".
Always use remote state (S3 + DynamoDB for locking) in production. Local state files can be lost or conflict in teams.
Key Takeaways
IaC makes infrastructure reproducible, version-controlled, and reviewable
Terraform is cloud-agnostic — one tool for AWS, Azure, GCP, and more
Always run terraform plan before apply to preview changes safely
Use modules for reusable infrastructure patterns across projects
Remote state with locking is essential for team workflows
Written by Surya Kanagaraj
Senior Fullstack Developer & AWS Cloud Engineer. Building production serverless apps on AWS. Available for freelancing.