Terraform Fundamentals

Terraform is the dominant infrastructure-as-code tool. You declare desired infrastructure in HCL (HashiCorp Configuration Language); Terraform reconciles the declaration against actual cloud state and applies changes. The model is declarative: describe what you want, not how to get there.

This page covers the core concepts and the patterns that make Terraform sustainable at scale.

The core concepts

Providers

A Terraform provider implements the API for a specific platform: AWS, Azure, GCP, Kubernetes, GitHub, Datadog, etc. The provider knows how to create, read, update, and delete each resource type.

```hcl

terraform {

required_providers {

aws = {

source = "hashicorp/aws"

version = "~> 5.0"

}

}

}

provider "aws" {

region = "us-west-2"

}

```

Providers are versioned. Pin them; floating versions break things.

Resources

A resource declares one piece of infrastructure:

```hcl

resource "aws_s3_bucket" "example" {

bucket = "my-bucket-name"

tags = {

Environment = "production"

}

}

```

Terraform creates the bucket if it doesn't exist; updates it if the declaration changes; deletes it if removed from config.

State

Terraform tracks the mapping from declared resources to actual cloud resources in a state file. State is the source of truth for what Terraform manages.

State storage is critical:

- Local state: fine for solo work, breaks for teams

- Remote state (S3 + DynamoDB lock): standard for production

- Terraform Cloud: managed remote state with collaboration features

State must be shared and locked. Two engineers running `apply` simultaneously without locking corrupt the state.

Plan and apply

```bash

terraform plan # show what would change

terraform apply # actually change it

```

`plan` is the safety net. Always review before applying. CI/CD typically requires plan output in PRs before apply is allowed.

Modules

Reusable bundles of resources:

```hcl

module "vpc" {

source = "terraform-aws-modules/vpc/aws"

version = "~> 5.0"

name = "my-vpc"

cidr = "10.0.0.0/16"

}

```

The community has high-quality modules for common patterns. Use them instead of writing from scratch.

Patterns at scale

Workspace per environment

Terraform workspaces (or separate state files) isolate environments. Common: dev, staging, production each with its own state. The same code applies; the variables differ.

Module composition

Larger projects compose modules:

```

infrastructure/

├── modules/

│ ├── vpc/

│ ├── ecs-cluster/

│ └── rds-postgres/

└── environments/

├── dev/

│ └── main.tf (uses the modules)

└── prod/

└── main.tf

```

Modules encode patterns; environments wire them together.

Variables and outputs

Modules declare inputs (variables) and outputs:

```hcl

variable "instance_type" {

type = string

default = "t3.medium"

}

output "instance_id" {

value = aws_instance.example.id

}

```

Outputs from one module become inputs to another. This is the wiring.

Secrets management

Don't put secrets in state files. Use:

- **Provider for secrets**: AWS Secrets Manager, HashiCorp Vault, etc.

- **Sensitive variable**: marks output as sensitive (won't show in CLI output)

- **External secret injection**: pass secrets at apply time, not stored in code

What Terraform doesn't do well

Imperative operations

"Run this script on the instance" — Terraform handles infrastructure, not configuration. For that, use Ansible, Chef, cloud-init, or container images.

Application deployment

Terraform creates infrastructure; deploying application code on it is a separate concern. CI/CD tools handle that.

Drift detection at scale

Terraform tracks what it manages; drift outside Terraform (someone clicks in the console) requires `terraform plan` to detect, and the response is awkward.

Alternatives

Pulumi

IaC in real programming languages (TypeScript, Python, Go, C#). More flexible than HCL; familiar control flow. Trade-off: less standardized; smaller ecosystem; more code complexity for simple cases.

AWS CDK

Cloud Development Kit — code that generates CloudFormation. AWS-specific. For AWS-only shops, sometimes preferred over Terraform.

CloudFormation

AWS's native IaC. Mature; tightly integrated with AWS. Less popular than Terraform because CloudFormation's evolution is slow and Terraform's multi-cloud story is appealing.

For most multi-cloud or even single-cloud usage, Terraform remains the default.

Common failure patterns

- **Local state in team environments.** Use remote state with locking.

- **Hardcoded values everywhere.** Use variables; parameterize per environment.

- **Massive monolithic Terraform.** Refactor into modules; smaller blast radius.

- **Manual state changes.** Editing state directly is dangerous; rare cases need it.

- **No CI/CD.** Apply from local machines means no audit, no review.

- **Provider version drift.** Pin versions; upgrade deliberately.

Further Reading

- [AwsFundamentals](AwsFundamentals) — Most common Terraform target

- [CloudNativeApplicationDesign](CloudNativeApplicationDesign) — What you provision

- [CloudSecurityFundamentals](CloudSecurityFundamentals) — Secrets, IAM

- [MonorepoVsPolyrepo](MonorepoVsPolyrepo) — Where Terraform code lives

- [CloudPlatforms Hub](CloudPlatformsHub) — Cluster index