Definition
- Terraform -- an open-source Infrastructure as Code tool from HashiCorp that lets you declare cloud infrastructure in HCL configuration files.
- Declarative -- you describe the desired end state and Terraform figures out the API calls needed to reach it.
- State file -- a JSON file (terraform.tfstate) that records every real resource Terraform has created and maps it back to your configuration.
- terraform plan -- a dry-run command that computes the diff between your configuration, the state, and the real cloud, without changing anything.
- terraform apply -- the command that executes the plan, makes real API calls, and updates the state file.
- Drift -- when someone changes a resource manually in the console so reality no longer matches the state file.
Imagine National Bank of India wants to open a new branch. The old way is calling the carpenter, electrician, and painter one by one, telling each verbally what to do, and hoping nobody forgets anything. Infrastructure as Code is writing one detailed blueprint that says this branch needs two teller counters, one vault, three ATMs, and this exact network layout. Terraform reads that blueprint and builds everything exactly as written. If next month you add a line saying one more ATM, Terraform sees that only the ATM is new and installs just that, touching nothing else.
Understanding the Concepts
What is Terraform?
Terraform is an open-source Infrastructure as Code tool from HashiCorp. Instead of clicking through a cloud console to create servers and databases, you write configuration files in HCL (HashiCorp Configuration Language) that declare the desired end state. Terraform reads these files, builds a dependency graph, and figures out the correct order of API calls. You never say how to create a resource -- you only say what it should be.
# main.tf -- declare a PostgreSQL database for account ledger
provider "aws" {
region = "ap-south-1"
}
resource "aws_db_instance" "ledger_db" {
identifier = "nbi-ledger-db"
engine = "postgres"
engine_version = "15.4"
instance_class = "db.r6g.large"
allocated_storage = 100
db_name = "ledger"
username = var.db_username
password = var.db_password
skip_final_snapshot = false
tags = {
Service = "account-ledger"
Environment = var.environment
}
}
How does the state file work?
The state file, usually named terraform.tfstate, is Terraform's memory. It records every real resource Terraform has created and maps it back to your configuration. When you run Terraform again, it reads the state, calls the cloud provider to check current reality, compares both against your .tf files, and computes the difference. Without state, Terraform would have no way of knowing that the database it sees is the same one it created last week.
# State file is JSON -- never edit manually
cat terraform.tfstate | jq '.resources[0].instances[0].attributes.identifier'
"nbi-ledger-db"
How does terraform plan work?
The plan command is the dry run. It computes what Terraform intends to do and prints a diff. A plus sign means a resource will be created, a tilde means it will be modified in place, and a minus sign means it will be destroyed. For a bank, this preview is essential because you want to see that a change will destroy the production database before it happens.
terraform plan
Terraform will perform the following actions:
# aws_db_instance.ledger_db will be created
+ resource "aws_db_instance" "ledger_db" {
+ identifier = "nbi-ledger-db"
+ engine = "postgres"
+ instance_class = "db.r6g.large"
+ allocated_storage = 100
}
Plan: 1 to add, 0 to change, 0 to destroy.
How does terraform apply work?
The apply command executes the plan. By default it shows the diff again and waits for you to type yes. Once confirmed, it makes the real API calls and updates the state file. In a pipeline you save the plan to a file and apply that exact file so nothing drifts between preview and execution.
# Save plan to file
terraform plan -out=tfplan
# Apply exactly that saved plan
terraform apply tfplan
aws_db_instance.ledger_db: Creating...
aws_db_instance.ledger_db: Creation complete after 4m12s [id=nbi-ledger-db]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Why do we use Infrastructure as Code?
Infrastructure as Code gives four key benefits. First, version control -- everything is in Git, so you get full history of who changed what and why, and you can roll back. Second, repeatability -- staging and production come from the same code with only a variable file differing, so environments are genuinely identical. Third, peer review -- infrastructure changes go through a pull request just like application code. Fourth, self-documenting -- the .tf files are the documentation of your infrastructure.
# variables.tf -- same code, different values per environment
variable "environment" {
description = "Environment name (dev, staging, production)"
type = string
}
variable "db_username" {
description = "Database admin username"
type = string
sensitive = true
}
variable "db_password" {
description = "Database admin password"
type = string
sensitive = true
}
# staging uses smaller instance
terraform apply -var-file=staging.tfvars
# production uses larger instance -- same code
terraform apply -var-file=production.tfvars
What is drift and how does Terraform detect it?
Drift happens when someone changes a resource manually in the cloud console, so reality no longer matches the state file. The next terraform plan detects this and shows the drift as a diff. Terraform apply will revert the manual change back to what the code says. This is why disciplined teams forbid manual console edits -- the code must always be the single source of truth.
# Someone manually increased storage to 200 in the console
terraform plan
# aws_db_instance.ledger_db will be updated in-place
~ resource "aws_db_instance" "ledger_db" {
~ allocated_storage = 200 -> 100
# (other attributes unchanged)
}
Plan: 0 to add, 1 to change, 0 to destroy.
How does Terraform fit into a CI/CD pipeline?
Engineers never run apply from their laptops against production. They open a pull request, the CI pipeline runs terraform plan and posts the diff as a comment, a human approves, and the pipeline runs terraform apply using a locked-down role with short-lived credentials.
# .github/workflows/terraform.yml
name: Terraform
on:
pull_request:
paths: ['infra/**']
jobs:
plan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform init
working-directory: infra/ledger
- run: terraform plan -out=tfplan
working-directory: infra/ledger
- run: |
terraform show -no-color tfplan > plan.txt
gh pr comment $PR_NUMBER --body "$(cat plan.txt)"
working-directory: infra/ledger
apply:
needs: plan
if: github.event.review.state == 'approved'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform init && terraform apply -auto-approve tfplan
working-directory: infra/ledger
How is Terraform different from CloudFormation?
Terraform is cloud-agnostic with a plugin ecosystem supporting hundreds of providers. CloudFormation is AWS-native with managed state. Both are valid choices, and the decision depends on multi-cloud needs and team skills.
| Feature | Terraform | CloudFormation |
|---|---|---|
| Cloud scope | Multi-cloud + SaaS providers | AWS only |
| Language | HCL | YAML / JSON |
| State | Self-managed (S3 + DynamoDB) | AWS-managed (invisible) |
| Rollback | Fix-forward | Automatic rollback |
| Preview | terraform plan | Change Sets |
What should a senior engineer know?
A senior engineer knows that the state file must be stored remotely in S3 with encryption and DynamoDB locking so multiple engineers can work safely. They know that drift detection is automatic on the next plan, that modules give reusable, reviewed building blocks, and that the plan output is the single most important artifact to review before any infrastructure change in a bank.
# backend.tf -- remote state with locking
terraform {
backend "s3" {
bucket = "nbi-tf-state"
key = "ledger/production/terraform.tfstate"
region = "ap-south-1"
dynamodb_table = "nbi-tf-locks"
encrypt = true
}
}
Visual Overview
Infrastructure as Code Workflow
──────────────────────────────
┌────────────────┐ ┌────────────────┐ ┌────────────────┐
│ .tf files │ │ State file │ │ Real Cloud │
│ (desired) │ │ (remembered) │ │ (actual) │
└───────┬────────┘ └───────┬────────┘ └───────┬────────┘
│ │ │
└──────────┬───────────┘──────────────────────┘
│
▼
┌────────────────┐
│ terraform plan │ compare all three
│ (dry run) │ print the diff
└───────┬────────┘
│
▼
┌────────────────┐
│ human reviews │
│ the diff │
└───────┬────────┘
│ approve
▼
┌────────────────┐
│ terraform apply │ make API calls
│ update state │ update state file
└───────┬────────┘
│
▼
┌────────────────┐
│ Real Cloud now │
│ matches .tf │
└────────────────┘
Key Takeaway
Terraform is a declarative Infrastructure as Code tool. Instead of clicking through a console, you declare the desired end state in configuration files and Terraform figures out the API calls. It maintains a state file that records every resource it has created, and the plan command compares your configuration, the state, and the real cloud to show a diff without changing anything. The apply command then executes that diff and updates the state.
The real value of Infrastructure as Code shows up in three ways. Staging and production come from the same code with only a variable file differing, so environments are genuinely identical. Every change goes through a pull request where a teammate can see the plan output before anything runs. And because everything lives in Git, when auditors ask who changed the backup retention and when, the answer is one git blame away.
Drift is the concept to always remember. If someone edits a resource by hand in the console, reality no longer matches the state file, and the next plan immediately shows that drift as a diff. Disciplined teams forbid manual console edits because the code must be the single source of truth.
Remember one sentence: terraform plan shows you the diff before apply makes it real, and the code in Git is always the single source of truth for your infrastructure.
---