Terraform Course
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:
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.microis 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_iponly 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 asvar.environment. - string interpolation —
"web-server-${var.environment}"embeds the variable value inside a string. Results inweb-server-prodwhen 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 reference —
aws_instance.web_server.public_ipreads thepublic_ipattribute 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
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.