Terraform Lesson 1 – What Is Terraform | Dataplexa
Section I · Lesson 1

What Is Terraform?

Every cloud team eventually hits the same wall — infrastructure that only one person understands, environments that drift apart, and no written record of how anything was built. Terraform was built to solve exactly that.

This lesson covers

The problem Terraform solves → What Infrastructure as Code means → How Terraform works → Providers explained → Your first real configuration → The core four-command workflow → Why the industry chose Terraform

The Problem

Before Terraform, building cloud infrastructure meant logging into a console and clicking through menus. Create a server here. Configure a database there. Set up the network manually. Hope you remember every setting you chose — because nothing was written down.

Now do that for three environments. Development, staging, production. Each one slightly different because different people set them up on different days. A bug that exists in production cannot be reproduced locally because the infrastructure is subtly different. Nobody knows why.

Then the production database gets accidentally deleted. The person who built it left six months ago. The team spends two days rebuilding from memory. This was the reality for most engineering teams — and it is the exact problem Infrastructure as Code was invented to solve.

The Analogy

A construction company does not show up on site and build a house from memory. They work from blueprints — every measurement specified, every material listed. If the house burns down, the blueprints survive and anyone can rebuild it exactly. Your .tf files are those blueprints. The cloud is the construction site. Terraform is the foreman who reads them and builds everything to spec.

What Terraform Is

Terraform is an open-source Infrastructure as Code tool built by HashiCorp, first released in 2014. You write files that describe what your infrastructure should look like. Terraform reads those files and creates, modifies, or destroys real cloud resources to match.

The critical word is declarative. You do not tell Terraform how to build things step by step. You describe what you want the end result to look like — and Terraform figures out how to get there. This is what makes it fundamentally different from a shell script, and fundamentally safer to use in production.

Approach How it works Run it twice?
Shell script Step-by-step instructions — imperative Errors — resources already exist
Terraform Describe desired end state — declarative Safe — nothing changes if already correct

How Terraform Works

Three things are always involved when Terraform runs — your configuration files, the state file, and the cloud provider. Here is how they connect:

Your .tf Files main.tf variables.tf outputs.tf Desired state Terraform Engine Reads config files Reads state file Calculates the diff Calls provider APIs The brain State File terraform.tfstate Records everything Terraform built The memory Cloud Provider AWS / Azure GCP / Kubernetes Real infrastructure The reality

Terraform reads your config and the state file, calculates what needs to change, then calls the cloud APIs to make it happen

Notice the state file. Most beginners do not expect this. Terraform keeps a record of every resource it has ever built in a file called terraform.tfstate. This is how it knows what already exists. Without it, Terraform would recreate everything from scratch on every run. State is one of the most important concepts in this entire course — it gets its own section later.

Providers

Terraform itself does not know how to create an AWS server or a Google Cloud bucket. That knowledge lives in separate plugins called providers. A provider is a plugin that translates your Terraform configuration into the specific API calls a platform understands.

Think of Terraform as a universal remote control. The remote does not know the infrared codes for your Samsung TV — those live in the device profile you load into it. Providers are those device profiles. The AWS provider knows every AWS API. The Azure provider knows every Azure API. Terraform downloads the provider automatically when you run terraform init. There are over 3,000 providers available — covering cloud platforms, databases, DNS services, monitoring tools, and more.

Your First Configuration

This is the simplest real Terraform configuration you can write. It creates one virtual server on AWS. Read through it carefully — do not worry about memorising syntax yet. Focus on understanding what each part is saying.

New terms:

  • provider block — declares which cloud platform to use and which region to build in.
  • resource block — declares one piece of infrastructure. Format is always resource "type" "local_name". The type tells Terraform what to create. The local name is how you refer to it elsewhere in your config.
  • ami — the server image (operating system + base software). AMI IDs are region-specific.
  • instance_type — how much CPU and RAM the server gets. t2.micro is the smallest — one vCPU, 1GB RAM, free tier eligible.
  • tags — key-value labels attached to the resource. They do not affect how the resource behaves — they are metadata for humans.
# main.tf

provider "aws" {
  region = "us-east-1"
}

resource "aws_instance" "my_server" {
  ami           = "ami-0c55b159cbfafe1f0"  # Amazon Linux 2
  instance_type = "t2.micro"

  tags = {
    Name        = "MyFirstServer"
    Environment = "dev"
    ManagedBy   = "Terraform"
  }
}

Note: No AWS account needed yet. Installation and setup is covered in Lesson 6. For now, read the code and understand what each block is doing.

$ terraform plan

Terraform will perform the following actions:

  # aws_instance.my_server will be created
  + resource "aws_instance" "my_server" {
      + ami           = "ami-0c55b159cbfafe1f0"
      + instance_type = "t2.micro"
      + public_ip     = (known after apply)
      + tags          = {
          + "Environment" = "dev"
          + "ManagedBy"   = "Terraform"
          + "Name"        = "MyFirstServer"
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

$ terraform apply

  Enter a value: yes

aws_instance.my_server: Creating...
aws_instance.my_server: Still creating... [10s elapsed]
aws_instance.my_server: Creation complete after 32s [id=i-0abc123def456789]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

What just happened?

  • The + symbol means this resource will be created. A ~ means modify. A - means destroy. Always read these carefully before confirming.
  • (known after apply) — some values like public_ip only exist after AWS creates the resource. Terraform cannot know them in advance so it shows this placeholder.
  • Terraform asked for confirmation. You must type "yes" explicitly. This is intentional — it is your last chance to review before real infrastructure changes.
  • id=i-0abc123def456789 — AWS assigned this ID to the new server. Terraform stores it in the state file so it can manage this resource in every future run.

Real-World Example — Variables and Outputs

Real teams never hardcode values directly into resource blocks. When values are hardcoded, the same configuration cannot be reused across environments — you would need separate copies for dev, staging, and prod. Variables solve this. Outputs surface important information after Terraform runs.

New terms:

  • variable block — declares an input parameter. It has a description, a type, and a default value. Pass a different value at runtime and the same config produces different infrastructure.
  • var.name — how you reference a variable inside your config. variable "environment" is referenced as var.environment.
  • string interpolation"web-server-${var.environment}" embeds the variable value inside a string. Results in web-server-prod when environment is prod.
  • output block — prints a value after apply. Used to surface IP addresses, resource IDs, and connection strings. Also used to pass data between modules.
  • resource attribute referenceaws_instance.web_server.public_ip reads the public_ip attribute from the resource Terraform just created.
# variables.tf

variable "region" {
  description = "AWS region to deploy into"
  type        = string
  default     = "us-east-1"
}

variable "instance_type" {
  description = "EC2 instance size"
  type        = string
  default     = "t2.micro"
}

variable "environment" {
  description = "Deployment environment: dev, staging, or prod"
  type        = string
  default     = "dev"
}

# main.tf

provider "aws" {
  region = var.region
}

resource "aws_instance" "web_server" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = var.instance_type

  tags = {
    Name        = "web-server-${var.environment}"
    Environment = var.environment
    ManagedBy   = "Terraform"
  }
}

# outputs.tf

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

output "server_instance_id" {
  description = "AWS-assigned instance ID"
  value       = aws_instance.web_server.id
}
$ terraform apply -var="environment=prod" -var="instance_type=t3.small"

  # aws_instance.web_server will be created
  + resource "aws_instance" "web_server" {
      + ami           = "ami-0c55b159cbfafe1f0"
      + instance_type = "t3.small"
      + tags          = {
          + "Environment" = "prod"
          + "ManagedBy"   = "Terraform"
          + "Name"        = "web-server-prod"
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

  Enter a value: yes

aws_instance.web_server: Creation complete after 34s [id=i-0def987abc654321]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

server_instance_id = "i-0def987abc654321"
server_public_ip   = "54.211.89.132"

The Core Workflow

Every Terraform project follows the same four commands — in the same order, every time. This workflow never changes regardless of the cloud provider, the team size, or the complexity of the infrastructure.

terraform init Downloads providers Sets up backend Run once per project terraform plan Previews all changes Nothing is built Always safe to run terraform apply Executes the plan Calls provider APIs Requires confirmation terraform destroy Removes everything Terraform built Requires confirmation

terraform init

Reads your configuration, identifies which providers you need, and downloads them from the Terraform Registry. Also sets up your state backend. Run this once when starting a new project, and again whenever you add a new provider. Never modifies infrastructure.

terraform plan

Compares your configuration against the current state of your infrastructure and calculates exactly what needs to change. Outputs a diff — additions with +, modifications with ~, deletions with -. Completely safe. Nothing is created, changed, or destroyed. Run it as often as you need.

terraform apply

Executes the plan and makes real changes to your infrastructure. Always shows you the plan first and requires you to type "yes" before proceeding. Updates the state file after every resource is processed. If a resource fails, Terraform stops and reports the error — it never silently continues past a failure.

terraform destroy

Removes all resources managed by the current configuration. Reads the state file, determines every resource it created, and deletes them in reverse dependency order. Essential for cleaning up temporary environments — spin up for testing, run your tests, destroy everything with one command and stop paying for it.

Common Mistakes

Confusing Terraform with Ansible or Chef

Terraform provisions infrastructure — it creates servers, databases, and networks. Ansible and Chef configure what is already running — they install software and manage files. They solve different problems and are often used together. Terraform builds the server. Ansible configures it.

Changing Terraform-managed resources manually in the console

If Terraform creates a server and you then change its settings in the AWS console, the state file no longer reflects reality. The next terraform apply will revert your manual change back to what the configuration says. The rule is absolute: if Terraform owns it, all changes go through Terraform.

Skimming the plan output before typing yes

The summary line says "1 to add" — but the detail shows a database flagged for destruction and recreation. That means data loss. Read every line of every plan before confirming. The modification symbol ~ and deletion symbol - are where production incidents come from.

One habit worth building from day one

Add ManagedBy = "Terraform" to the tags of every resource you create. In a production environment with hundreds of resources, this single tag answers the most common infrastructure question instantly — was this created by Terraform or manually? Without it, nobody knows whether it is safe to delete a resource or whether some process silently depends on it.

Practice Questions

1. What is the name of the language Terraform uses to write configuration files?



2. Which command downloads the provider plugins your configuration needs?



3. What is the name of the file Terraform uses to record all infrastructure it has created?



Quiz

1. Terraform is declarative. What does that mean?


2. What are Terraform providers?


3. When is it acceptable to modify a Terraform-managed resource directly in the AWS console?


Up Next · Lesson 2

Why Infrastructure as Code Matters

You understand what Terraform is. The next lesson goes deeper into why Infrastructure as Code became a professional standard — the specific disasters it prevents, the advantages it gives teams that adopt it properly, and how it changed the relationship between development and operations forever.