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 provider
is 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
.tf
configuration 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 init
and 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