Back to Blog
Cloud13 min readJun 2026

Infrastructure as Code with Terraform, Start Here

Clicking around a cloud console works until you need a second environment, a teammate, or to remember what you built last month. This is the from-zero introduction to Terraform, what Infrastructure as Code is, the plan/apply loop, state, providers, resources, variables, and outputs, with real, copy-pasteable code.

TerraformIaCCloudFoundations
SB

Sri Balaji

Founder ยท TheSimplifiedTech

On this page

Why clicking in consoles stops working

Your first cloud resources come from clicking. You open the AWS console, click through a wizard, create a server. It works, and clicking feels productive. Then reality arrives: you need an identical staging environment and can't remember the 14 settings you picked. A teammate asks how the network is configured and the only honest answer is "let me click around and check." Something breaks and nobody knows what changed, because clicks leave no record. Clicking doesn't scale, doesn't repeat, and doesn't remember.

The fix is to describe your infrastructure in text files, commit them to Git, and let a tool build exactly what the files say. That's Infrastructure as Code (IaC), and Terraform is the most widely used tool for it. This article gets you from zero to understanding the whole core loop, and writing real Terraform you can run.

Who this is for

Anyone who's created cloud resources by clicking and sensed there must be a better way. No Terraform experience needed. Knowing roughly what a cloud server or network is helps, but we explain as we go. Examples use AWS; Terraform works with every major provider.

What Infrastructure as Code actually is

Infrastructure as Code means writing down what your infrastructure should look like in files you can version, review, and reuse, then having a tool make reality match the files.

The mental shift is from *doing* to *describing*. You don't perform the steps to create a server. You write down "I want one server, this size, in this network," and Terraform figures out the steps. If the server doesn't exist, it creates it. If it already matches, it does nothing. The analogy that makes it click:

๐Ÿ“ A written recipe cardYour .tf files
๐Ÿ›’ A shopping + cook plan before you startterraform plan
๐Ÿ‘จโ€๐Ÿณ Actually cooking the dishterraform apply
๐Ÿ““ A note of exactly what's in the fridge nowTerraform state
Clicking is following a recipe by memory every time. IaC is the written recipe, anyone can reproduce the exact dish.

Because the recipe is a text file, it goes in Git. Now your infrastructure has history, code review, and a single source of truth. "What changed?" becomes git log. "Make me another environment" becomes copying a folder.

Console clicks vs Terraform

Clicking the consoleTerraform
RepeatableNo, you redo it by handYes, same files, same result
Record of what existsIn your memoryIn Git, readable by anyone
Code review before changesImpossibleIt's a pull request
Make a second environmentClick everything againCopy the folder, change a variable
Undo a changeHope you rememberRevert the commit, re-apply
Good forQuick experiments, learningAnything you'll keep
Same goal, a running environment, but only one of these survives a team, a second environment, and time.

Pro tip

It's fine to click around when you're exploring and learning. The rule of thumb: the moment a resource matters enough that you'd be upset if it vanished, it belongs in code.

The four words that are all of Terraform

Terraform looks big, but the day-to-day vocabulary is tiny. Learn these four and you can read almost any Terraform file.

  1. 1

    Provider

    The plugin that knows how to talk to a specific cloud, aws, azurerm, google. You declare which provider(s) you're using and where.

  2. 2

    Resource

    One thing you want to exist, a server, a network, a database. The bulk of your code is resource blocks.

  3. 3

    Variable

    An input you can change without editing the logic, region, instance size, environment name. This is what makes one set of files reusable across environments.

  4. 4

    Output

    A value Terraform prints after it builds, the server's IP, the database endpoint, so you (or other tooling) can use it.

Your first real Terraform

Let's write something that runs. Start by declaring the provider, which cloud, and which region. The region comes from a variable so the same files work anywhere.

providers.tf
hcl
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = var.region   # value comes from variables.tf
}

Now declare inputs as variables. Giving them defaults makes them optional; leaving a default off makes Terraform ask (or require) a value.

variables.tf
hcl
variable "region" {
  description = "AWS region to deploy into"
  type        = string
  default     = "eu-west-1"
}

variable "environment" {
  description = "Environment name, e.g. dev or prod"
  type        = string
  default     = "dev"
}

Then the actual resource. This is a real, free-tier-friendly S3 bucket, a good first resource because it's simple and hard to break. Notice how it reads the variable to tag itself.

main.tf
hcl
resource "aws_s3_bucket" "app_data" {
  bucket = "thesimplifiedtech-${var.environment}-app-data"

  tags = {
    Environment = var.environment
    ManagedBy   = "terraform"   # so humans know not to click-edit it
  }
}

Finally, an output so Terraform tells you what it made instead of making you go look.

outputs.tf
hcl
output "bucket_name" {
  description = "Name of the created bucket"
  value       = aws_s3_bucket.app_data.bucket
}

The plan / apply loop

Terraform has exactly one workflow you'll run thousands of times. init once to download the provider, then the loop: plan to preview, apply to make it real.

workflow.sh
bash
# Once per project: download providers, set up the working dir
terraform init

# The safety net: shows EXACTLY what will be created/changed/destroyed.
# Changes nothing. Read this every single time.
terraform plan

# Make reality match the files. Asks you to type 'yes' first.
terraform apply

# When you're done with everything: tear it all down cleanly
terraform destroy

terraform plan is the feature that makes Terraform safe to learn on. It's a dry run, it reads your files, checks what currently exists, and prints the diff: + for create, ~ for change, - for destroy. Nothing happens until you run apply and type yes.

Always read the plan, especially the minus signs

A `-` (destroy) or `-/+` (replace) in a plan means a resource is about to be deleted and recreated. On a database, that's data loss. The plan is telling you before it happens, but only if you read it. Never apply a plan you didn't look at.

State: how Terraform remembers

Here's the concept beginners trip over. How does Terraform know your bucket already exists so it doesn't make a second one? It keeps a state file, a record of every resource it created and its real-world ID. On the next plan, it compares three things: your files (desired), the state (last known), and the real cloud (actual).

This is also idempotency in action: run apply ten times with no file changes and Terraform does nothing nine of those times, because state already matches your files. "Make it so" is safe to repeat, that's the whole promise of IaC.

State is precious, and a secret

The state file (terraform.tfstate) can contain sensitive values and is the source of truth Terraform trusts. Two rules: never commit it to Git (it can hold secrets), and for any team, store it in remote state (an S3 bucket with locking) so two people can't apply at once and corrupt it. Solo learning on your laptop is fine; teams need remote state from day one.

Common mistakes that cost hours

  1. Running apply without reading the plan. The plan literally tells you what's about to be destroyed. Skipping it is how people accidentally delete production databases.
  2. Editing resources in the console after Terraform made them. Now reality and state disagree. Next apply may revert your click, or get confused. If it's in Terraform, change it in Terraform.
  3. Committing the state file or .tfvars secrets to Git. State can contain secrets; tfvars often hold passwords. .gitignore both before your first commit.
  4. No remote state on a team. Two people apply at once with local state and corrupt it. Use a remote backend with locking the moment more than one person touches the code.
  5. Hardcoding values that should be variables. Region, sizes, and names hardcoded means you can't reuse the files for a second environment. If it changes between environments, make it a variable.
  6. Not pinning provider versions. Without a version constraint, a provider upgrade can change behaviour under you. Pin with ~> and upgrade deliberately.

Where to go next

The whole article in 6 lines

  • **IaC** = describe infrastructure in version-controlled files; a tool makes reality match them.
  • Terraform's vocabulary is tiny: **provider** (which cloud), **resource** (a thing), **variable** (input), **output** (result).
  • The loop is **init โ†’ plan โ†’ apply**. `plan` is a free dry run, always read it.
  • **State** is how Terraform remembers what it built; it powers idempotency and must never be committed.
  • Don't click-edit what Terraform made, change it in code, or state and reality drift.
  • Variables turn one set of files into many environments; that reuse is the whole point.

Reading Terraform is easy; the fluency comes from running the loop yourself until plan and apply feel automatic. Go build something real:

Create that S3 bucket with Terraform today, change the environment variable, and apply it again to make a second one. The moment you watch one variable spin up a whole new environment, you'll never want to click a console again.

Want to go deeper?

This article covers concepts taught hands-on in the Cloud Engineer and DevOps career paths, with real terminal labs, production scenarios, and structured lessons.