DEV Community

Cover image for Don’t Touch Terraform Before Avoiding These 5 Rookie Mistakes

Don’t Touch Terraform Before Avoiding These 5 Rookie Mistakes

The 5 mistakes that quietly destroy your workflow — and how to fix them.

🌟 Introduction

Welcome back, Devs!

A few weeks ago, I shared 5 Best Security Practices for Terraform. That guide was more for folks who already work with Terraform day in and day out — the ones managing infra at scale, reviewing modules, and pushing changes through CI/CD pipelines.

But what about the beginners?

The ones who just wrapped up the basics of DevOps — Linux, Networking, Docker, Git — and are now stepping into the cloud world. For them, Infrastructure as Code can feel… well, intimidating at first. Terraform looks simple from the outside, but when you actually start writing configurations, the learning curve hits hard. And it’s totally normal — IaC is a tough nut to crack initially.

So to make your journey smoother and confusion-free, I’m back with today’s blog, where we’ll break down the Top 5 Mistakes Beginners Make While Learning Terraform — and how you can avoid them.

Without further ado… let’s get started!


🌟 Before We Dive In… Do This First

Before we dive deep into the mistakes, let’s get one thing out of the way — make sure you’ve got Terraform ready on your system. No matter how good the guide is, nothing makes sense unless you’ve actually installed the CLI and can run those sweet terraform init and terraform apply commands.

Since I’m an AWS Community Builder, I usually stick to AWS as my cloud provider for demos and explanations. If you’re following along, you’ll need to connect Terraform to your AWS account. You can do that in two ways:

  1. Export AWS credentials directly in your terminal

    (AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY)

    Works fine, but not the best option for long-term use.

  2. Install the AWS CLI (recommended)

    This is cleaner, more secure, and helps you manage multiple profiles easily.

    Just create an IAM user with the right permissions and run aws configure.

If you don’t know how to set that up — don’t worry. I’ve already covered the entire process in my Beginner’s Guide to Terraform. You can check it out here:

👉 https://blog.praveshsudha.com/getting-started-with-terraform-a-beginners-guide#heading-step-1-install-the-aws-cli

Once your CLI and AWS credentials are set, you’re all ready to explore the mistakes beginners make and how you can avoid them.


❌ Mistake 1: Treating Terraform Like a Scripting Tool

This is hands-down the most common beginner mistake.

Most folks who get introduced to Terraform have already touched at least one programming language — Python, Go, Rust, maybe even Bash scripting. And because of that prior experience, they naturally assume Terraform will behave the same way:

“I wrote line 1 first, so Terraform will execute that first… right?”

Nope. Not at all.

Terraform is not a scripting tool.

It doesn’t run your code line-by-line.

It doesn’t care about the order in which you wrote your resources.

Terraform is declarative, not imperative.

Instead of following your code from top to bottom, Terraform reads all the resources in your configuration and builds something called a dependency graph. This graph tells Terraform which resources depend on which other resources — and that determines the execution order.

So beginners often get confused:

“Why is Terraform not creating things in the order I wrote them?”

Because Terraform is smarter than that. It looks at dependencies, not line numbers.

Moral of the story:

With Terraform, you don’t explain how to create each step. You only declare what you want — like an EC2 instance, security groups, and a VPC — and Terraform figures out the “how” automatically.

Once you understand this mindset shift, Terraform becomes much easier (and honestly, more fun) to work with.


Mistake 2: Hardcoding Everything Instead of Using Variables

If you’re anything like me, you love going through official docs whenever you start learning a new tech. And if you visit the Terraform documentation, you’ll notice something instantly:

Most of their example configurations hardcode values.

Region? Hardcoded.

AMI ID? (Got from data type).

App name, DB name, instance type? All hardcoded.

And honestly — that's fine when you're just starting out. Hardcoding helps beginners understand the structure of a resource without worrying about variables, files, or module structures.

But once you get a basic understanding of how Terraform works…

hardcoding becomes your worst enemy.

Let me explain with a simple example.

Say you’ve deployed a two-tier application on AWS — your VPC, ALB, EC2, RDS, security groups, everything. Now there’s a new feature request, and you don’t want to deploy the changes in the same environment.

So you decide to replicate the environment.

If everything is hardcoded, you’re now stuck manually changing names and identifiers for every single resource.

Painful.

Time-consuming.

Highly prone to breaking things.

The Fix: Use Variables Like a Pro

Store all your important attributes inside a variables.tf file.

This gives you a clean, centralized location for every configuration value your entire project depends on.

In the above scenario, if your resources use variables, all you need to do is change a value in one place — and Terraform will automatically reflect it everywhere.

Here’s how you define a variable in Terraform:

variable "instance_type" {
  default = "t2.micro"  # EC2 Instance Type
}
Enter fullscreen mode Exit fullscreen mode

Clean, reusable, scalable — and exactly how real-world Terraform is written.


❌ Mistake 3: Mixing Manual Changes Through the AWS Console

This one is a classic beginner trap.

When you provision infrastructure using Terraform, it stores a full blueprint of your resources inside the terraform.tfstate file. This file represents the current state of your infrastructure — basically Terraform’s memory of what exists.

Now imagine you want to update something small, like renaming an EC2 instance.

You open the AWS Console, click on the instance, change the name, hit save, and boom — done.

Simple, right?

Yes. But also… very wrong.

Making manual console changes creates something called drift — a mismatch between:

  • what actually exists in AWS

  • what Terraform thinks exists (according to the state file)

This drift becomes a huge headache because Terraform will now get confused about what's changed, what needs to be replaced, or what should not exist at all. For beginners, handling drift is even more overwhelming because it's not always obvious where things went wrong.

Here’s the golden rule:

If you provision resources using Terraform,

update or delete them using Terraform only.

Avoid the temptation of "quick fixes" in the AWS Console. A few clicks today can cause hours of debugging tomorrow.

Moral of the story:

Treat Terraform as your single source of truth.

No ClickOps. No shortcuts.


Mistake 4: Ignoring Terraform Resource Dependencies

Terraform is pretty smart when it comes to understanding relationships between resources. It automatically builds a dependency graph to figure out what needs to be created first and what depends on what.

Most of the time, this works beautifully.

But sometimes… Terraform needs a little help.

There are scenarios where Terraform cannot infer dependencies on its own — especially when two resources don’t have an obvious reference to each other. That’s where beginners get stuck.

For example:

  • Applying an S3 Bucket Policy before the bucket is actually created

  • Applying IAM role attachments before the IAM role itself exists

  • Creating a Lambda permission before the Lambda function is ready

In such cases, Terraform might try to create things in the wrong order, leading to errors.

The Fix: Use depends_on Smartly

Terraform gives us an escape hatch — the depends_on meta-argument.

With depends_on, you can explicitly tell Terraform:

“Hey, this resource should only be created after this other resource is fully ready.”

It ensures the correct and predictable order of execution.

Example use case:

resource "aws_s3_bucket_policy" "bucket_policy" {
  bucket = aws_s3_bucket.my_bucket.id

  policy = data.aws_iam_policy_document.example.json

  depends_on = [
    aws_s3_bucket.my_bucket
  ]
}
Enter fullscreen mode Exit fullscreen mode

Now Terraform knows for sure: Bucket first → Policy second.

Moral of the story:

Understand how Terraform creates its dependency graph, and use depends_on wisely when Terraform can’t figure things out on its own.


❌ Mistake 5: Thinking Terraform Is Only About init, plan, and apply

I still remember when I started learning Terraform.

I watched a bunch of YouTube tutorials, and almost every single one followed the exact same pattern:

  • Write config in main.tf, provider in provider.tf, vars in variables.tf, outputs in outputs.tf

  • Run terraform init

  • Run terraform plan (and let’s be honest, most beginners skip this 😅)

  • Run terraform apply --auto-approve

  • And at the end, terraform destroy

And that’s it.

End of tutorial.

Done.

“You now know Terraform.” 🙃

Except… that’s not the full story.

Terraform is not just about those three commands. There are many other commands that help you:

  • write cleaner, more readable code

  • avoid silly mistakes

  • prevent accidental deployments

  • stick to best practices from day one

But beginners (including me back in the day) completely ignore them.

Here are a few essential ones:

🔹 terraform plan (Seriously, use it)

Before applying, always check the plan.

It shows you what Terraform will create, modify, or delete.

Skipping this step is how disasters happen — and trust me, I’ve been guilty of this too. 😅

🔹 terraform fmt (Fix your code automatically)

Your code may work, but if it looks like a messy bowl of noodles, nobody wants to maintain it.

terraform fmt formats your HCL beautifully and keeps your files consistent.

🔹 terraform validate (Catch misconfigurations early)

Sometimes your code “looks” right but contains subtle mistakes — wrong types, bad arguments, misplaced blocks, etc.

terraform validate helps detect these before you even think about applying them.

Moral of the story:

Make fmt, validate, and plan a daily habit.

They will save you from so many unnecessary headaches.


🌟 Hands-On: Deploying a Static Portfolio Website on an S3 Bucket

Alright, that’s enough theory — now let’s actually get our hands dirty.

To make everything we discussed more practical, we’ll deploy a static portfolio website on an S3 bucket using Terraform.

The complete code is available here:

👉 https://github.com/Pravesh-Sudha/terra-projects

Once you open the repo, navigate to the terra-mistakes directory. Inside it, you’ll find multiple Terraform files and a static/ folder. The static directory contains two HTML files:

  • index.html — your main portfolio page

  • error.html — fallback page for unexpected errors

Inside the main.tf, we’re:

  • creating an S3 bucket

  • enabling static website hosting

  • uploading both HTML files

  • attaching a bucket policy to allow public access

You’ll also notice something important:

  • We didn’t hardcode values; even in this small project, the bucket name is stored in variables.tf

  • We used depends_on so Terraform knows to create the Public Access Block before applying the bucket policy

These are the exact practices that prevent the mistakes we discussed earlier.

Run These Commands to See Everything in Action

Open your terminal inside the terra-mistakes directory and run:

terraform init          # Initialize provider plugins
terraform fmt           # Fix indentation, syntax, and formatting
terraform validate      # Detect any surface-level misconfigurations
terraform plan          # Preview what Terraform will provision
terraform apply --auto-approve   # Deploy the S3 website
Enter fullscreen mode Exit fullscreen mode

Once the resources are created, Terraform will output the Website URL from the output.tf file.

Note:

This project is deployed in us-east-1, and the S3 website endpoint URL is hardcoded for that region.

If you want to deploy in another region, update both the provider and output.tf accordingly.

Now, open the URL in your browser — and boom! 🎉

Your portfolio website is live on S3.


Updating the Policy the Right Way

Let’s say you want to add delete object permission to the bucket policy.

The beginner instinct?

Head straight to the AWS Console → IAM → update the policy manually.

But we don’t do ClickOps here.

Remember: Terraform is your single source of truth.

So instead, update your HCL code inside the bucket policy:

Statement = [
  {
    Sid       = "PublicReadGetObject"
    Effect    = "Allow"
    Principal = "*"
    Action    = ["s3:GetObject", "s3:DeleteObject"]  # Added delete permission
    Resource  = "${aws_s3_bucket.site_bucket.arn}/*"
  }
]
Enter fullscreen mode Exit fullscreen mode

Then apply the changes:

terraform apply --auto-approve
Enter fullscreen mode Exit fullscreen mode

Terraform will detect the change, update only the policy, and keep everything consistent — no drift, no confusion.

To cross check the changes, go to S3 Console → Navigate to the bucket and click on Permissions tab and See the Bucket Policy.

Cleaning Up

When you're done experimenting, don’t forget to delete everything:

terraform destroy --auto-approve
Enter fullscreen mode Exit fullscreen mode

This removes all AWS resources cleanly so you don’t get billed unnecessarily.


🌟 Conclusion

Learning Terraform as a beginner can feel overwhelming — not because the tool is hard, but because Infrastructure as Code requires a different mindset. The mistakes we covered today are extremely common, and almost every Terraform practitioner (including me 😅) has made them at some point.

But the good news?

Once you start writing declarative code, using variables wisely, avoiding ClickOps, understanding dependencies, and making fmt, validate, and plan part of your workflow — Terraform becomes a powerful, predictable, and enjoyable tool to work with.

Take your time, practice often, and break things safely.

Every small experiment makes you a better DevOps engineer.

If you followed along with the hands-on demo, you now have a static website deployed on AWS using clean, beginner-friendly Terraform. That’s a solid milestone — great job, Dev! 🚀

Feel free to explore more projects, improve your configurations, or even contribute to the repo. And if you ever get stuck, you know where to find me.

Connect With Me

If you enjoyed this blog or learned something new, let’s connect:

Let’s keep building, learning, and automating together! 🚀

Top comments (0)