First Terraform Project Setup

Learn how to set up your first Terraform project step by step. This Terraform foundations tutorial covers core concepts, hands-on exercises, and troubleshooting to get you started with infrastructure as code.

Focus: set up your first terraform project

Sponsored

So you're ready to stop clicking through cloud consoles and start treating your infrastructure like real code. The pain is real: every manual server, every ad-hoc firewall rule, every 'who changed that?' conversation. Setting up your first Terraform project is the moment you move from chaos to versioned, reviewable, reproducible infrastructure—and it's easier than you think. In this lesson, you'll scaffold a project, write your first configuration, and run the plan-and-apply loop that will become second nature.

The problem this lesson solves

When you create resources by hand in a console or with ad-hoc scripts, you inherit a pile of invisible problems:

  • Drift: someone tweaks a setting, and now your staging environment doesn't match production.
  • No history: you can't answer 'what changed last Tuesday?' without going on a scavenger hunt.
  • Fear of change: every edit feels risky because there's no way to preview it.

Terraform fixes all of that with a single idea: describe your infrastructure in declarative files, then let Terraform figure out the steps to make reality match your description. Once you set up your first Terraform project, you'll have a repeatable workflow that any engineer can pick up.

Core concept / mental model

Think of Terraform as a recipe and a chef that follows it exactly. The recipe is your configuration files—they say what the final dish (infrastructure) should look like. The chef reads the recipe, checks what's already in the kitchen (your current cloud resources), and then does only the steps needed to reach the desired state.

Three key pieces to keep in your head:

  • Configuration files.tf files that declare your desired infrastructure.
  • Providers — plugins that know how to talk to a specific cloud or service (AWS, Azure, GCP, etc.).
  • State — Terraform's in-memory and on-disk record of what currently exists. It uses a file named terraform.tfstate by default.

Here's the high-level flow:

  1. You write .tf files.
  2. You run terraform init to download providers and set up the working directory.
  3. You run terraform plan to see what Terraform would do.
  4. You run terraform apply to make it happen.

How it works step by step

Let's break down the workflow that every Terraform engineer follows—it never changes, only the resources you declare do.

1. Design your project layout

A minimal project is just a folder with a .tf file. But even at the start, use a clean structure:

my-first-tf-project/
├── main.tf          # your main configuration
├── variables.tf     # input variables (optional but recommended)
└── outputs.tf       # useful output values (optional)

2. Write your first configuration

Create a main.tf that tells Terraform which provider to use and what to create. Here's a simple AWS example:

# main.tf
terraform {
  required_version = ">= 1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

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

resource "aws_s3_bucket" "my_bucket" {
  bucket = "my-first-tf-bucket-2024"
}

Pro tip: Always pin provider versions to avoid surprise upgrades. The ~> 5.0 syntax means 'any 5.x version, but not 6.0'.

3. Initialize the project

Run terraform init in your project directory. This downloads the AWS provider plugin and sets up the working directory.

terraform init

Expected output will show that Terraform has initialized, and it will create a .terraform directory (which you should add to your .gitignore!).

4. Plan and apply

Now the exciting part. Run terraform plan to see a preview. Then, if you're happy, run terraform apply.

terraform plan
terraform apply

When you apply, Terraform will ask for confirmation, then create the resource. At the end, it shows you what was created and saves the state.

5. Clean up when done

If you're just practicing, remove everything with terraform destroy so you don't get charged for idle resources.

terraform destroy

This is the full life cycle—create, update, destroy—and it's the foundation of everything you'll do with Terraform.

Hands-on walkthrough

Let's build something slightly more interesting: a web server on AWS using the free tier. This will exercise variables, outputs, and a real resource.

Step 1: Create variables.tf

# variables.tf
variable "instance_name" {
  description = "Name tag for the instance"
  type        = string
  default     = "my-first-instance"
}

variable "region" {
  description = "AWS region"
  type        = string
  default     = "us-east-1"
}

Step 2: Update main.tf

# main.tf
terraform {
  required_version = ">= 1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = var.region
}

resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"  # Amazon Linux 2 (check for your region)
  instance_type = "t2.micro"

  tags = {
    Name = var.instance_name
  }
}

output "instance_id" {
  value = aws_instance.web.id
}

output "public_ip" {
  value = aws_instance.web.public_ip
}

Step 3: Run the commands

terraform init
terraform plan
terraform apply -auto-approve

You'll see Terraform print the two outputs: the instance ID and public IP. Congratulations—you just provisioned a real server with code!

Note: The AMI ID changes by region and over time. Visit the AWS documentation to find a current one, or use a data source (which you'll learn later).

Step 4: Tear it down

terraform destroy -auto-approve

This removes the instance. You've now seen the complete cycle.

Compare options / when to choose what

You'll quickly discover there are several ways to organize and run Terraform. Here's a quick comparison to help you choose right for your situation.

Approach Best for Trade-offs
Single .tf file Small tests, first project Everything in one place, fine for tiny setups
Multiple .tf files (by resource) Medium projects Clean separation, but still a single state
Modules Reusable components More upfront design, but saves tons of time later
Terraform Cloud Team collaboration Remote state, runs in their cloud, costs after free tier
Terragrunt DRY configurations Another tool to learn, but reduces repetition

For your first project, stick with a simple flat structure. As your infrastructure grows, you'll naturally migrate to modules and remote state.

Troubleshooting & edge cases

Even the simplest project can throw a curveball. Here are the most common issues you'll face—and how to fix them.

terraform init fails with "Failure loading plugin"

  • Cause: Network issue or wrong provider source.
  • Fix: Check your internet connection, verify the provider name in required_providers, and try again.

"Error creating: InvalidParameter: KeyPair... not found"

  • Cause: You're trying to use an SSH key that doesn't exist in your AWS account.
  • Fix: Either create the key pair in AWS first, or remove that block if you don't need it.

terraform plan shows changes you didn't make

  • Cause: Someone else changed the resource outside Terraform.
  • Fix: This is expected drift. Run terraform apply to bring it back into sync, or update your config if the drift is intentional.

"InvalidAMIName" or ami not found

  • Cause: The AMI ID is region-specific or outdated.
  • Fix: Find the correct ID in your region. Better: learn to use data "aws_ami" to look up the latest automatically.

Permissions denied

  • Cause: Your AWS credentials don't have permission to create the resource.
  • Fix: Ensure your IAM user/role has the necessary policies (e.g., AmazonS3FullAccess for the bucket example).

terraform apply hangs or times out

  • Cause: Slow network or the cloud provider is being slow.
  • Fix: Set a longer timeout in the provider block, or check the provider's status page.

What you learned & what's next

You now understnad the core idea behind setting up your first Terraform project: write declarative config, init, plan, apply, and destroy. You've also seen how to use variables, outputs, and troubleshoot common errors. That's the foundation of everything Terraform.

In the next lesson, we'll dive into Terraform state—what it is, why it matters, and how to manage it safely with remote backends like S3. You'll learn to avoid the classic 'state file in a shared folder' mistake and collaborate with your team without fear of overwriting each other.

For now, practice what you've learned: create a simple project, change a resource, and observe how Terraform reports the diff. The more you touch it, the more natural it becomes.

Practice recap

Create a minimal project that provisions an S3 bucket and an EC2 instance (or any free-tier resource). Change the bucket name or instance type and run terraform plan to see the diff. Then run terraform apply and finally terraform destroy to clean up. This will solidify the init-plan-apply-destroy cycle in your muscle memory.

Common mistakes

  • Committing the .terraform directory and terraform.tfstate file to version control — this can leak secrets and break collaboration; always add them to .gitignore.
  • Hard-coding credentials in main.tf — instead use environment variables or a shared credentials file, and avoid ever exposing secrets in code.
  • Skipping terraform plan before apply — you lose the chance to catch risky changes before they hit production.
  • Using the same state file for multiple projects — this mixes unrelated infrastructure and causes lock conflicts; create a separate directory or workspace per project.

Variations

  1. Use Terraform Cloud or remote backends (like S3 with DynamoDB locking) to store state centrally and enable team collaboration.
  2. Structure your configuration with modules from day one for reusable components — start small, but think about how you'll grow.
  3. Adopt a tool like Terragrunt to reduce repetition and manage dependencies, especially when your infrastructure spans multiple environments.

Real-world use cases

  • A startup provisions a staging environment with an EC2 instance, RDS database, and security groups using a single terraform apply.
  • A DevOps engineer sets up a shared Terraform project that spins up an S3 bucket and IAM roles for application logging.
  • A team uses Terraform to create a complete Kubernetes cluster (EKS) with managed node groups and peered VPCs in a repeatable way.

Key takeaways

  • Terraform treats infrastructure as declarative code, letting you preview changes with plan and apply them with apply.
  • A project needs at minimum main.tf, and you'll typically add variables.tf and outputs.tf as you grow.
  • Always run terraform init first to download providers—it's the bootstrap for everything.
  • terraform destroy cleans up resources and avoids unnecessary cloud charges during practice.
  • State file and .terraform directory must be protected—never commit them to git unless you use a remote backend.
  • The core workflow (init → plan → apply → destroy) is the same for every Terraform project, no matter how complex.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.