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
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 —
.tffiles 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.tfstateby default.
Here's the high-level flow:
- You write
.tffiles. - You run
terraform initto download providers and set up the working directory. - You run
terraform planto see what Terraform would do. - You run
terraform applyto 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.0syntax 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 applyto 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.,
AmazonS3FullAccessfor 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
.terraformdirectory andterraform.tfstatefile 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 planbeforeapply— 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
- Use Terraform Cloud or remote backends (like S3 with DynamoDB locking) to store state centrally and enable team collaboration.
- Structure your configuration with modules from day one for reusable components — start small, but think about how you'll grow.
- 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
planand apply them withapply. - A project needs at minimum
main.tf, and you'll typically addvariables.tfandoutputs.tfas you grow. - Always run
terraform initfirst to download providers—it's the bootstrap for everything. terraform destroycleans up resources and avoids unnecessary cloud charges during practice.- State file and
.terraformdirectory 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.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.