Terraform
Terraform
Core
Init, Plan, Apply
- terraform init
- Set up providers & backend in that directory
terraform init
- terraform plan
- Preview changes
terraform plan
- terraform apply
- Make changes (add -auto-approve to skip prompt)
terraform apply
Core Concept

1. Providers
- Providers is a Terraform Plugin to interact with API
- Best practice: Providers must be located in a separate file ex:
terrafrom.tf - Example of providers which
Terraform Support
# terraform.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5. 0"
}
}
}
provider "aws" {
region = "us-east-1"
}
Local provideris used for creating and managing resources on your local machine (no API interaction)
# terraform.tf
terraform {
required_providers {
local = {
source = "hashicorp/local"
version = "2.5.3"
}
}
}
2. Resources + Meta-Arguments
- Actual components that will be define
- Best practice: Resources must be located in
main.tf - Syntax:
resource "type" "resource_name" {}
- Example of local provider (Requirements & Optionals):
# main.tf (local provider)
resource "local_file" "local" {
# requirement
filename = "<relative path>/filename.txt"
# or use a relative path command with ${}
# filename = "${path.module}/filename.txt"
#optional
content = "This is a local file created by Terraform"
}
- Meta-Arguments:
- Special arguments that can be used with every resource
- They work with every resource type to control how Terraform creates or manages them.
depends_on
- Forces an explicit dependency between resources.
- Useful when Terraform can’t automatically detect the dependency.
- Example:
resource "aws_s3_bucket" "example" {
bucket = "my-bucket"
}
resource "aws_s3_bucket_policy" "example_policy" {
bucket = aws_s3_bucket.example.id
policy = data.aws_iam_policy_document.example.json
depends_on = [aws_s3_bucket.example] # ensures bucket is created first
}
count
- Creates multiple instances of the same resource.
- You can access each instance with an index ([0], [1], etc.).
- Example:
resource "aws_instance" "servers" {
count = 3
ami = "ami-123456"
instance_type = "t2.micro"
}
- → Creates 3 EC2 instances.
for_each
- Similar to count, but instead of an index, it uses a map or set of strings.
- Gives more control over naming and referencing.
- Example:
resource "aws_s3_bucket" "buckets" {
for_each = toset(["dev", "staging", "prod"])
bucket = "myapp-${each.key}"
}
- → Creates 3 uniquely named buckets.
provider
- Lets you specify which provider configuration a resource should use, especially when multiple providers of the same type exist.
- Example:
provider "aws" {
region = "us-east-1"
alias = "east"
}
provider "aws" {
region = "us-west-2"
alias = "west"
}
resource "aws_instance" "west_server" {
provider = aws.west
ami = "ami-654321"
instance_type = "t2.micro"
}
lifecycle
- Controls special behaviors for resources during apply/destroy.
- Common options:
create_before_destroy= true → ensures a new resource is made before deleting the old one.prevent_destroy= true → protects critical resources from being destroyed.ignore_changes= [field] → tells Terraform to ignore changes to certain fields.
- Example:
3. State management
Definitions
-
What It Is
- The state file is like Terraform’s “notebook.”
- It records all resources that Terraform has created, modified, or deleted.
- It acts as Terraform’s database for keeping track of infrastructure.
-
Current vs Desired State
- Desired State = what you define in your
.tfconfiguration files. - Current State = what Terraform knows already exists (stored in the state file).
- Terraform compares the two and makes changes to bring the current state in line with the desired state.
- Desired State = what you define in your
-
How It Works in Practice
- At first, the state file is empty because nothing exists.
- When you run
terraform apply, Terraform:- Creates the infrastructure.
- Updates the state file with details of the created resources (like IDs, attributes, etc.).
- If you later change or delete resources in your config, Terraform compares with the state file and applies only the necessary updates.
-
State File Format
- Stored as JSON in
terraform.tfstate. - Contains metadata (Terraform version, provider info).
- Stores details of each resource: type, name, attributes, IDs, and configuration.
- Stored as JSON in
-
Why It’s Important
- Terraform relies on it to know what’s already been provisioned.
- Without it, Terraform would not know whether resources already exist and might recreate or duplicate them.
- It enables Terraform’s declarative approach: always moving the current state toward the desired state.
State Sub Command
- Usage:
terraform state <subcommand> [options] [args]- List all sub commands:
terraform state -h
- List all sub commands:
terraform state list, List resources in the stateterraform state mv, Move an item in the stateterraform state pull, Pull current state and output to stdoutterraform state push, Update remote state from a local state fileterraform state replace-provider, Replace provider in the stateterraform state rm, Remove instances from the stateterraform state show, Show a resource in the stateterraform state show <specific resources>, gives information of that resource only
IMPORTANT: State Drift
- State Drift:
- Occur when someone delete resources manually from the Provider's UI
- Solution:
terraform initand thenterraform apply(Recommend)- Init helps to compare the actual infra and current state file
- apply create the missing/difference between the two, hence create missing resource(s) + config the state file
terraform refresh(Not Recommend)- If the deletion is intentional
- terraform refresh will not change anything in the infra, but it will changes the current state file
- However, this command doesn't consider the
resource file