DEV Community

Cover image for Terraform Explained: From "What Even Is This?" to Actually Getting It 🚀
Yash Sonawane
Yash Sonawane

Posted on

Terraform Explained: From "What Even Is This?" to Actually Getting It 🚀

Posted by a 3rd-year engineering student who broke prod at 2AM and lived to tell the tale.


The 2AM Problem Nobody Warns You About

Picture this: You've manually set up an EC2 instance on AWS. Security groups, IAM roles, VPC config — all done by hand through the console. It works. You feel like a genius.

Then your teammate accidentally deletes it.

You stare at the screen. You can't remember which settings you chose. The documentation you meant to write is a blank Notion page. It's 2AM and you have a demo in six hours.

This is exactly the situation that made me stop clicking around in the AWS console and actually sit down to learn Terraform. And honestly? I wish I'd started sooner.


So What Problem Does Terraform Actually Solve?

Let me give you a real example instead of a textbook answer.

Say you need to set up this on AWS:

  • An EC2 instance (your server)
  • A security group (firewall rules)
  • An S3 bucket (file storage)
  • An IAM role (permissions)

If you're doing this manually through the AWS console, here's what happens:

  1. You click through 15 screens to create the EC2 instance
  2. You forget to attach the IAM role
  3. You go back, fix it
  4. You need to do the exact same thing for your staging environment
  5. You mess up one setting — staging and production are now different for no reason
  6. A new teammate joins and has zero idea what you built or why

With Terraform, you write all of that as code. One file. Version controlled. Reproducible. If staging and prod need to look the same, you run the same code. If a teammate joins, they read the file and understand everything immediately.

That's the core promise: your infrastructure becomes code, not a mystery.


Infrastructure as Code — Let Me Explain It Like You're My Classmate

Okay forget the formal definition for a second.

You know how developers write code to build apps? The app doesn't exist until someone runs the code. Infrastructure as Code (IaC) is the same idea — but instead of building a web app, you're building servers, networks, databases, and cloud resources.

Before IaC, sysadmins would SSH into servers and manually configure everything. It worked, but:

  • It was slow
  • It was inconsistent (every server was slightly different)
  • It wasn't documented anywhere
  • If it broke, nobody knew how to rebuild it exactly

IaC flips this. You describe what you want in a file, run a command, and the tool builds it for you. Every time. Exactly the same.

Think of it like a recipe. A chef can make the same dish 100 times using the same recipe. Before recipes, every dish was slightly different depending on who was cooking that day.


Why I Chose Terraform Over Other Tools

There are other IaC tools — AWS CloudFormation, Ansible, Pulumi. Here's why I went with Terraform as a learner:

It's cloud-agnostic. The same tool works for AWS, GCP, Azure, and more. I don't want to learn three different tools just to try different clouds.

Huge community. When I get stuck (which is often), there's a Stack Overflow answer, a blog post, or a GitHub issue that's already solved my exact problem.

It's what companies actually use. I checked job listings and DevOps/Cloud roles almost always list Terraform. Learning it felt like a real investment.

The learning curve felt worth it. It's not easy, but it clicks after a few projects.


Core Concepts — The Stuff That Actually Matters

🔌 Providers

A provider is basically a plugin that tells Terraform which cloud or service to talk to.

provider "aws" {
  region = "us-east-1"
}
Enter fullscreen mode Exit fullscreen mode

This tells Terraform: "Hey, we're working with AWS, and we want resources in us-east-1." There are providers for GCP, Azure, Kubernetes, GitHub, Datadog — pretty much anything.


🧱 Resources

Resources are the actual things you want to create — an EC2 instance, an S3 bucket, a database.

resource "aws_instance" "my_server" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
}
Enter fullscreen mode Exit fullscreen mode

The format is always: resource "type" "local_name". The local name is just for you to reference it elsewhere in the code.


📦 Variables

Instead of hardcoding values everywhere, you use variables. This makes your code reusable.

variable "instance_type" {
  default = "t2.micro"
}

resource "aws_instance" "my_server" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = var.instance_type
}
Enter fullscreen mode Exit fullscreen mode

Now if you want to change the instance type, you change it in one place — not hunt through 10 files.


🗂️ State File

This one confused me the most at first. Terraform keeps a file called terraform.tfstate that tracks what it has already created. It uses this to figure out what needs to change when you update your config.

Two important things I learned the hard way:

  • Never edit it manually. It's JSON and it looks editable, but messing with it will confuse Terraform badly.
  • Don't commit it to GitHub if it has secrets. Use remote state (like S3 + DynamoDB) for team projects.

⚙️ The Core Commands

terraform init     # Downloads the providers, sets up the working directory
terraform plan     # Shows you what WILL happen before you do anything
terraform apply    # Actually creates/changes the infrastructure
terraform destroy  # Tears everything down
Enter fullscreen mode Exit fullscreen mode

terraform plan is your best friend. Always run it before apply. It shows you exactly what Terraform is going to do — create, change, or destroy — so there are no surprises.


📝 HCL (HashiCorp Configuration Language)

HCL is the language you write Terraform configs in. It's not JSON, not YAML — it's its own thing. But it's pretty readable once you get used to it. You saw examples above — it looks clean and logical once you stop being afraid of it.


A Real Example: Launching an EC2 Instance on AWS

Here's a simple, working Terraform setup to launch an EC2 instance with a security group:

# main.tf

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

variable "instance_type" {
  default = "t2.micro"
}

resource "aws_security_group" "allow_ssh" {
  name        = "allow_ssh"
  description = "Allow SSH inbound traffic"

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_instance" "my_server" {
  ami                    = "ami-0c55b159cbfafe1f0"
  instance_type          = var.instance_type
  vpc_security_group_ids = [aws_security_group.allow_ssh.id]

  tags = {
    Name = "MyTerraformServer"
  }
}

output "instance_ip" {
  value = aws_instance.my_server.public_ip
}
Enter fullscreen mode Exit fullscreen mode

Run it:

terraform init
terraform plan
terraform apply
Enter fullscreen mode Exit fullscreen mode

That's it. No clicking through the AWS console. No forgetting a setting. Just code.


Beginner Mistakes (I Made All of These)

1. Not using terraform plan before apply
I just ran apply directly a few times. Once it modified a production resource I didn't mean to touch. Always plan first.

2. Committing the state file or .terraform folder to Git
Add these to your .gitignore immediately:

.terraform/
*.tfstate
*.tfstate.backup
Enter fullscreen mode Exit fullscreen mode

3. Hardcoding sensitive values
Never put your AWS secret key, database password, or any credential directly in .tf files. Use environment variables or tools like AWS Secrets Manager.

4. Not understanding that Terraform is declarative
You describe what you want, not how to get there. It took me a while to stop thinking procedurally.

5. Manually changing resources after Terraform created them
If you create an EC2 instance with Terraform and then go resize it in the console manually, Terraform won't know. Next time you run plan, it'll look like a drift and might try to undo your change.


How Terraform Fits Into Real DevOps Workflows

In actual companies, Terraform doesn't just run on someone's laptop. It's wired into CI/CD pipelines.

A typical setup looks like this:

  • Developer opens a PR with infrastructure changes
  • CI (like GitHub Actions) runs terraform plan automatically and posts the output as a comment on the PR
  • After review and merge, CI runs terraform apply automatically
  • State is stored remotely in S3 with a DynamoDB lock so no two people apply at the same time

Tools like Terraform Cloud or Atlantis make this even smoother. You end up with a full audit trail of who changed what infrastructure, when, and why — just like code reviews for application code.

This is why knowing Terraform isn't just a nice-to-have in 2025. It's a core skill if you're serious about cloud or DevOps.


What I Actually Learned From This

  • Start small. One resource. One provider. Get it working.
  • Read the Terraform docs for the specific resource you're using — they're actually really good.
  • Remote state is not optional for team projects. Set it up early.
  • Treat your infra code like application code: review it, version it, document it.
  • terraform destroy is satisfying and also terrifying. Use it carefully.

Final Thoughts

Terraform is one of those tools that looks intimidating from the outside but makes total sense once you write your first working config. The concepts aren't complicated — it's just unfamiliar at first.

If you're a student or early-career engineer trying to get into DevOps or Cloud, learning Terraform alongside Docker and Kubernetes is a genuinely strong combination. It's the kind of skill that shows up in almost every job description I've seen.

I'm documenting my learning publicly — if you're on a similar journey, feel free to connect or check out my GitHub where I'm pushing small projects and notes as I go.

What's your experience with Terraform been like? Drop it in the comments — especially if you've made a mistake worse than mine 👇


Top comments (0)