Skip to main content
Navigation
HomeTechnical ReferenceJournalGitHubGitHub
Sidebar — toggle document categories via the logo
Categories

Why Terraform — Infrastructure as Code

Overview

Infrastructure as Code (IaC) means managing servers, networks, and databases the same way you manage application code — in version-controlled text files that can be reviewed, tested, and reproduced. Terraform is the leading IaC tool because of its declarative model, provider ecosystem, and state-based lifecycle management.

The problem with manual infrastructure

Without IaC, infrastructure management has well-known failure modes:

  • Click-ops: Configuring resources through web consoles is slow, error-prone, and impossible to reproduce or audit.
  • Snowflake servers: Manually tweaked servers diverge over time. No two environments are alike, so staging never matches production.
  • Configuration drift: An emergency fix applied directly to a server is lost on the next deployment because it wasn't captured in code.
  • No change history: Without version control, you can't see who changed what or roll back to a known-good state.

IaC solves these by making infrastructure repeatable, auditable, and automatable.

Why Terraform vs other tools

CategoryToolTerraform's advantage
Configuration managementAnsible, Chef, PuppetTerraform focuses on provisioning infrastructure; config mgmt tools focus on configuring software. They complement each other.
Cloud-native templatesCloudFormation (AWS), ARM (Azure), Deployment Manager (GCP)Terraform is multi-cloud — the same workflow works across AWS, Azure, GCP, and Kubernetes.
ScriptingBash, Python with SDKsTerraform is declarative: you describe the desired state, and Terraform figures out how to achieve it. Scripts require handling idempotency, error recovery, and state tracking manually.
PulumiUse familiar programming languagesTerraform uses HCL, a domain-specific language optimized for infrastructure. Pulumi uses general-purpose languages.

Declarative vs imperative

Terraform is declarative: you write what the infrastructure should look like, not the step-by-step instructions for building it.

# Declarative: "I want a web server with these properties"
resource "aws_instance" "web" {
ami = "ami-0fb653ca2d3203ac1"
instance_type = "t2.micro"
tags = { Name = "web-server" }
}

Compare with an imperative script that manually calls aws ec2 run-instances, waits for the instance to start, assigns tags in a separate call, checks error codes, and must handle partial failures. Terraform handles idempotency automatically — run apply twice, and the second time produces no changes because the resource already exists.

Key Terraform concepts for beginners

ConceptDescription
ProviderPlugin that interfaces with a specific cloud API (AWS, Azure, GCP, Kubernetes, etc.).
ResourceAn infrastructure object managed by Terraform — an EC2 instance, a database, a DNS record.
Data sourceRead-only query to fetch information about existing infrastructure (e.g., "find the default VPC").
VariableParameterizable input that makes configurations reusable across environments.
OutputValue exported from a configuration for use by other configurations or for display.
StateJSON file mapping configuration to real-world resources.
ModuleReusable, composable group of resources.

Bootstrapping a web server

A common first pattern: launch an EC2 instance and run a web server at boot time:

resource "aws_instance" "web" {
ami = "ami-0fb653ca2d3203ac1"
instance_type = "t2.micro"
availability_zone = "us-east-2a"

user_data = <<-EOF
#!/bin/bash
apt-get update -y
apt-get install -y apache2
systemctl start apache2
systemctl enable apache2
echo "<h1>Served by Terraform</h1>" > /var/www/html/index.html
EOF

tags = {
Name = "terraform-web"
}
}

output "public_ip" {
value = aws_instance.web.public_ip
description = "Public IP address of the web server"
}

What this does:

  • user_data runs a shell script when the instance first boots.
  • The script installs Apache, starts it, and writes a simple HTML page.
  • The output block displays the instance's public IP after creation.
  • Access http://<public_ip> in a browser to see the result.

When user_data changes

By default, Terraform does not replace an EC2 instance when user_data changes — it updates in-place. To force replacement (which runs the bootstrap script on a fresh instance), add:

resource "aws_instance" "web" {
# ... other settings ...

user_data_replace_on_change = true
}

The IaC mindset

  1. Everything as code: If it's in the AWS console, move it into Terraform.
  2. Never touch production by hand: Click-ops in production create drift. Apply changes through Terraform.
  3. Version everything: Configuration, state (in a backend), and module versions.
  4. Environments must be disposable: You should be able to terraform destroy and terraform apply to recreate any environment.

See also