Getting Started with Terraform

Install Terraform and deploy your first infrastructure

7 min read

Getting Started with Terraform

"Infrastructure as Code" sounds like something a consultant made up to charge more. But it's actually simple — you write config files that describe what you want, and Terraform makes it happen. No clicking around in cloud consoles, no forgetting what you changed last Tuesday.

What is Terraform?

So what does Terraform actually do?

Think of it as a very obedient robot:

  • You hand it a blueprint (config files) describing your infrastructure
  • It figures out what needs to change
  • It talks to your cloud provider and makes those changes

The key idea: you describe the end state ("I want 3 servers"), not the steps to get there. Terraform handles the how. It's like ordering food at a restaurant — you say what you want, not how to cook it.

Install Terraform

macOS (Homebrew)

brew tap hashicorp/tap
brew install hashicorp/tap/terraform

Linux (Ubuntu/Debian)

wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform

Windows

choco install terraform

Or download from terraform.io/downloads.

Verify Installation

Almost done? Not yet dude. Let's verify it actually installed:

terraform version

You should see something like Terraform v1.7.0. If you see that, you're golden!

Set Up AWS Credentials

"Wait, how does Terraform talk to AWS?"

Great question. Terraform needs permission to create resources — it's not going to hack into your AWS account. You need to give it credentials:

Option 1: Environment Variables

export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"
export AWS_REGION="us-east-1"

Option 2: AWS CLI Profile

aws configure

This creates ~/.aws/credentials — Terraform finds it automatically.

Option 3: IAM Role (on EC2/ECS)

If running on AWS, use IAM roles. No credentials to manage. This is the best option for production — we'll talk more about this later.

Your First Terraform Config

Alright, enough setup. Let's actually build something! Create a new directory:

mkdir learn-terraform && cd learn-terraform

Create main.tf:

# Configure the AWS provider
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

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

# Create an S3 bucket
resource "aws_s3_bucket" "my_bucket" {
  bucket = "my-first-terraform-bucket-12345"  # Must be globally unique

  tags = {
    Name        = "My First Bucket"
    Environment = "Learning"
  }
}

That's it. That's the whole config. This creates an S3 bucket in AWS. How cool is that?

The Terraform Workflow

Here's the thing — you'll use these three commands 95% of the time. Memorize them:

1. terraform init

Initialize the working directory:

terraform init

Output:

Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 5.0"...
- Installing hashicorp/aws v5.31.0...

Terraform has been successfully initialized!

This downloads the AWS provider plugin. Think of it as npm install for Terraform — run it once per project (or when you add new providers).

2. terraform plan

"Can I see what it's going to do before it actually does it?"

Yes! That's exactly what plan does — it's a preview, a dry run:

terraform plan

Output:

Terraform will perform the following actions:

  # aws_s3_bucket.my_bucket will be created
  + resource "aws_s3_bucket" "my_bucket" {
      + bucket = "my-first-terraform-bucket-12345"
      + id     = (known after apply)
      + tags   = {
          + "Environment" = "Learning"
          + "Name"        = "My First Bucket"
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

The + means "will be created". Nothing has happened yet — this is just a preview. Like looking at the receipt before you pay.

3. terraform apply

Time to make it real:

terraform apply

Terraform shows the plan again and asks for confirmation:

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

Type yes, hit Enter. Terraform creates the bucket.

aws_s3_bucket.my_bucket: Creating...
aws_s3_bucket.my_bucket: Creation complete after 2s [id=my-first-terraform-bucket-12345]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Boom! Check your AWS console — the bucket exists! You just created cloud infrastructure with a text file. Let that sink in.

Making Changes

"What if I need to change something?"

Just update the config file. Terraform figures out the diff. Change the tag in main.tf:

tags = {
  Name        = "My First Bucket"
  Environment = "Development"  # Changed from "Learning"
}

Run terraform plan:

  # aws_s3_bucket.my_bucket will be updated in-place
  ~ resource "aws_s3_bucket" "my_bucket" {
      ~ tags = {
          ~ "Environment" = "Learning" -> "Development"
            # (1 unchanged element hidden)
        }
    }

Plan: 0 to add, 1 to change, 0 to destroy.

The ~ means "will be modified" — not creating or destroying, just tweaking. Apply it:

terraform apply

Destroying Resources

Done playing around? Let's clean up so you don't get a surprise AWS bill:

terraform destroy
  # aws_s3_bucket.my_bucket will be destroyed
  - resource "aws_s3_bucket" "my_bucket" {
      - bucket = "my-first-terraform-bucket-12345"
      - tags   = {
          - "Environment" = "Development"
          - "Name"        = "My First Bucket"
        }
    }

Plan: 0 to add, 0 to change, 1 to destroy.

Do you really want to destroy all resources?

Type yes. Bucket gone. No more charges. Clean as a whistle.

What Just Happened?

Let's recap what actually happened behind the scenes:

  1. init — Downloaded the AWS provider plugin
  2. plan — Read your config, compared to current state, showed differences
  3. apply — Made API calls to AWS to create/update resources
  4. destroy — Made API calls to delete resources

Terraform also created a terraform.tfstate file. This tracks what resources exist — it's Terraform's memory. We'll cover state management in detail later — for now, just don't delete it. Seriously.

Project Files

After running, your directory looks like:

learn-terraform/
ā”œā”€ā”€ main.tf              # Your config
ā”œā”€ā”€ terraform.tfstate    # Current state (what exists)
ā”œā”€ā”€ .terraform/          # Provider plugins
└── .terraform.lock.hcl  # Provider version lock

Add to .gitignore:

.terraform/
*.tfstate
*.tfstate.*

Don't commit state files — they may contain secrets (passwords, API keys, the works). We'll cover remote state later.

Quick Reference

CommandWhat it does
terraform initInitialize, download providers
terraform planPreview changes
terraform applyApply changes
terraform destroyDelete everything
terraform fmtFormat code nicely
terraform validateCheck syntax

Common Mistakes

You will hit these. Everyone does.

Bucket name not unique

Error: creating S3 Bucket: BucketAlreadyExists

S3 bucket names are globally unique across all AWS accounts worldwide. Add random characters or your name to make it unique.

Wrong region

Resources created in unexpected region? Check your provider block or AWS_REGION env var.

No credentials

Error: No valid credential sources found

Set up AWS credentials (see above).

What's Next?

Look at you — you just went from zero to creating cloud infrastructure with a text file. You now know:

  • The init → plan → apply workflow (your new best friend)
  • How to read plan output (+ create, ~ modify, - destroy)
  • How to clean up with destroy

But main.tf was pretty basic. Time to learn HCL syntax and resources properly — things get a lot more interesting from here. Let's go!