Skip to content
ioob.dev
Go back

Terraform Part 1 — What Is Terraform

· 7 min read
Terraform Series (1/15)
  1. Terraform Part 1 — What Is Terraform
  2. Terraform Part 2 — Installation and First Deploy
  3. Terraform Part 3 — HCL Syntax
  4. Terraform Part 4 — Variables and Outputs
  5. Terraform Part 5 — Providers
  6. Terraform Part 6 — Resources and Dependencies
  7. Terraform Part 7 — Data Sources and Import
  8. Terraform Part 8 — State Management
  9. Terraform Part 9 — Modules
  10. Terraform Part 10 — Loops and Conditionals
  11. Terraform Part 11 — Workspaces and Environment Separation
  12. Terraform Part 12 — Kubernetes and Helm Providers
  13. Terraform Part 13 — CI/CD Integration
  14. Terraform Part 14 — Testing and Policy
  15. Terraform Part 15 — Practical Patterns and Pitfalls
Table of contents

Table of contents

The Moment You Get Tired of Clicking the Console

You’ve probably logged into the AWS Console and created an EC2 instance before. Pick a region, choose an AMI, select an instance type, create a security group, attach a key pair, and finally hit “Launch.” The first instance is exciting and fun.

The trouble starts when you need to create the same environment again. One for development, another for staging, yet another for production. The three environments are similar but subtly different. Which security group had port 22 open again? What was the instance type for staging? There’s no trace left of what you clicked in the console. The configuration notes you jotted down in Google Docs are out of sync with reality after just three weeks.

When someone says “replicate that environment to another region,” an entire day evaporates. Infrastructure built by clicking has no reproducibility. This is exactly the problem Terraform solves.

What Is Infrastructure as Code

Infrastructure as Code (IaC) is exactly what it sounds like. You define infrastructure as code. Cloud resources like servers, networks, storage, and databases are described in text files, and running those files creates the actual infrastructure in the cloud.

# Declare a single EC2 instance
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"

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

This file is the blueprint for your infrastructure. Running terraform apply causes Terraform to call the AWS API and create the actual instance. Run the same file in a different account and you get an identical instance.

Managing with code means you can use the tools developers are already familiar with for infrastructure too.

None of these happen naturally with console clicking. IaC is a declaration: “Let’s treat infrastructure operations like software development.”

Where Terraform Fits

Terraform is one of the most widely used IaC tools. HashiCorp released it as open source in 2014, and it has effectively become the standard for multi-cloud IaC.

Terraform’s character can be summed up in one line: A tool that manages multiple cloud providers declaratively using a single language (HCL).

Three words are key.

The last point — declarative — best represents Terraform’s philosophy. Let’s dig into this concept in the next section.

Declarative vs Imperative

When comparing IaC tools, the distinction between declarative and imperative always comes up. Terraform falls in the declarative camp.

Imperative means “do this, then do that” — listing steps one by one. Bash scripts are a classic example.

# Imperative — give instructions step by step
aws ec2 create-security-group --group-name web-sg --description "web"
aws ec2 authorize-security-group-ingress --group-name web-sg --protocol tcp --port 80 --cidr 0.0.0.0/0
aws ec2 run-instances --image-id ami-xxx --count 1 --instance-type t3.micro \
  --security-groups web-sg

The problem is that running this script twice throws an error saying the security group already exists. You have to write logic in the script yourself to “skip what’s already created and only create what’s missing.” As environments grow more complex, you end up in if-else hell.

Declarative is different. You only write “this state should exist.”

# Declarative — just describe the desired state
resource "aws_security_group" "web" {
  name = "web-sg"
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_instance" "web" {
  ami           = "ami-xxx"
  instance_type = "t3.micro"
  vpc_security_group_ids = [aws_security_group.web.id]
}

No matter how many times you apply this file, the result is the same. If it already exists, leave it alone; if it doesn’t, create it; if attributes have changed, fix them. This property is called idempotency. Terraform calculates the difference between the actual state and the declared state and makes only the necessary API calls.

The benefits of the declarative approach can be visualized as follows.

flowchart LR
    DEV[Developer writes .tf files] --> PLAN[terraform plan]
    PLAN -->|Calculate diff| DIFF{Current state vs<br/>Desired state}
    DIFF -->|Needs addition| CREATE[Create resource]
    DIFF -->|Needs modification| UPDATE[Update resource]
    DIFF -->|Needs deletion| DELETE[Delete resource]
    DIFF -->|No difference| NOOP[Do nothing]

The developer writes “this state should exist,” and Terraform figures out “the actions needed to reach that state.” This aligns closely with Kubernetes’ declarative philosophy as well.

How Terraform Works

You might be curious how the declarative approach is actually implemented. Terraform works by combining three things.

terraform plan compares these three. It shows you what’s new, what changed, and what disappeared by comparing what’s recorded in the State against the Configuration. terraform apply actually applies those differences.

flowchart TB
    USER[User]
    TF[Terraform Core]
    CFG[.tf files<br/>Desired state]
    STATE[(terraform.tfstate<br/>Recorded state)]
    PROV[Provider<br/>AWS/GCP/Azure...]
    CLOUD[(Actual cloud)]

    USER -->|Write| CFG
    USER -->|terraform apply| TF
    CFG --> TF
    STATE <--> TF
    TF <-->|API calls| PROV
    PROV <--> CLOUD

The especially important concept here is State. Terraform needs to remember “this resource is one I created” to know which resources to modify and which to delete. State will be covered in depth in a later part. For now, just remember that “Terraform has a file where it remembers its past.”

Terraform vs Other Tools

Terraform isn’t the only IaC tool. There are several similar-looking tools, each with a different focus. Understanding these differences matters when choosing Terraform in practice.

vs Ansible

Ansible is the most frequently compared tool. Both describe environments in YAML/HCL, but they cover different domains.

The two aren’t competitors — they’re more like a division of labor. A typical combination is creating EC2 with Terraform and installing nginx inside it with Ansible. Ansible is fundamentally imperative (Playbook tasks run in order), while Terraform is fully declarative.

vs AWS CloudFormation

CloudFormation is an IaC service built directly by AWS. It describes AWS resources in JSON/YAML.

If your organization only uses AWS, CloudFormation is a reasonable choice. But if you’re multi-cloud, or need to manage SaaS services outside AWS (Datadog, Cloudflare, GitHub), Terraform is much cleaner.

State management also differs. CloudFormation has AWS manage the state for you, so there’s less to worry about, but Terraform requires you to manage the State file yourself. In return, Terraform works the same way across any cloud.

vs Pulumi

Pulumi is a relatively new tool. It describes infrastructure using programming languages (TypeScript, Python, Go, etc.).

For complex scenarios where the expressive power of a programming language is needed (e.g., complex manifest generation logic), Pulumi has the advantage. On the other hand, if multiple team members need to understand and maintain the code at a similar level, Terraform’s “declarative DSL” constraint means a lower learning curve. Terraform does support expressions like loops and for, but full program flow control is not possible.

Comparison Summary

flowchart TB
    subgraph IMP[Imperative / Procedural]
        ANS[Ansible<br/>Server configuration management]
    end

    subgraph DEC[Declarative]
        TF[Terraform<br/>Multi-cloud]
        CF[CloudFormation<br/>AWS only]
        PU[Pulumi<br/>General-purpose language based]
    end

    subgraph SCOPE[Domain]
        INFRA[Infrastructure provisioning]
        CFG[Server internal configuration]
    end

    TF -.-> INFRA
    CF -.-> INFRA
    PU -.-> INFRA
    ANS -.-> CFG

Here’s a summary of why teams choose Terraform in practice.

What Terraform Doesn’t Solve

To truly understand a tool’s value, you need to know its boundaries. Terraform is not a silver bullet.

Terraform’s role is clear: A tool that declaratively manages the lifecycle (creation, modification, deletion) of cloud resources. By focusing on this role, it’s also easy to combine with other tools.

Before Taking the First Step

If you’ve read this far, you should have a sense of “why” Terraform is needed. Next comes the “how.” In the next part, we’ll actually install Terraform, set up an AWS profile, and spin up our first EC2 instance with code. We’ll learn the meaning of the four commands — terraform init, plan, apply, destroy — through hands-on experience.

The declarative philosophy clicks fastest when you learn it through practice. Let’s feel the difference from the console-clicking experience firsthand.


-> Part 2: Installation and First Deploy


Related Posts

Share this post on:

Comments

Loading comments...


Previous Post
Kubernetes Beginner Series 12 — Helm and Package Management
Next Post
Terraform Part 2 — Installation and First Deploy