As Terraform projects grow, keeping all configurations inside a single main.tf becomes difficult to manage. A well-organized file structure makes your Infrastructure as Code easier to read, scale, and maintain. Today’s focus is on learning how Terraform loads files and how to structure them properly.
How Terraform Loads Files
Before organizing resources into different files, it’s important to understand how Terraform treats them:
- Terraform loads all .tf files in the same directory.
- Files are processed in alphabetical (lexicographical) order.
- File names do not impact how Terraform behaves.
- All
.tffiles are merged into one configuration internally.
This means the file structure exists mainly for users, not for Terraform. You can divide files however you prefer as long as the content itself is valid.
Recommended Terraform File Structure
A clean and readable Terraform project often uses a structure like this:
project-root/
├── backend.tf # Remote backend configuration
├── provider.tf # Providers and default settings
├── variables.tf # Input variables
├── locals.tf # Local values (naming, tags)
├── main.tf # General resources
├── vpc.tf # VPC and networking
├── outputs.tf # Output values
├── terraform.tfvars # Values for variables
└── README.md # Documentation
This structure separates responsibilities clearly and keeps the project easy to navigate.
Why This Structure Helps
Separation of Concerns
Different resources stay in different files (networking, compute, storage, etc.).Easier Collaboration
Multiple team members can work on different parts without conflicts.Readability
It becomes easier to find specific resources or edit configurations.Scalability
As infrastructure grows, the structure remains manageable.
Reorganized Terraform Code
The simplified and clean version of the restructured files based on the given configuration.
backend.tf
terraform {
backend "s3" {
bucket = "my-aws-terraform-demo-bucket-123456789"
key = "dev/terraform.tfstate"
region = "us-east-1"
use_lockfile = "true"
encrypt = true
}
}
provider.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "6.23.0"
}
}
}
provider "aws" {
region = var.region
}
variables.tf
variable "region" {
description = "AWS Region"
type = string
}
variable "environment" {
description = "Environment name like dev, stage, prod"
type = string
}
variable "ami_id" {
description = "AMI ID for the ec2 instance"
type = string
}
variable "instance_type" {
description = "EC2 instance type"
type = string
}
variable "bucket_name" {
description = "S3 Bucket name"
type = string
}
variable "vpc_cidr_block" {
description = "CIDR block for the VPC"
type = string
}
locals.tf
locals {
common_tags = {
Environment = var.environment
Project = "Terraform-Demo"
Owner = "DevOps-Team"
}
# full bucket name with environment prefix
full_bucket_name = "${var.environment}-${var.bucket_name}-${random_string.suffix.result}"
}
main.tf
resource "aws_instance" "my_instance" {
ami = var.ami_id
instance_type = var.instance_type
}
resource "aws_s3_bucket" "terraform_bucket" {
bucket = var.bucket_name
}
resource "aws_vpc" "terraform_vpc" {
cidr_block = var.vpc_cidr_block
}
outputs.tf
resource "aws_instance" "my_instance" {
ami = var.ami_id
instance_type = var.instance_type
}
resource "aws_s3_bucket" "terraform_bucket" {
bucket = var.bucket_name
}
resource "aws_vpc" "terraform_vpc" {
cidr_block = var.vpc_cidr_block
}
terraform.tfvars
region = "us-east-1"
environment = "dev"
ami_id = "ami-id"
instance_type = "t2.micro"
bucket_name = "my-aws-terraform-demo-bucket-123456789"
vpc_cidr_block = "10.0.0.0/16"
Best Practices for File Organization
- Use clear and consistent naming.
- Group similar resources together.
- keep files focused on specific areas.
- Avoid putting everything in
main.tf. - Document your structure in a README.
- Use modules for reusable components.
- Keep files readable and under manageable size.
Useful Commands
terraform validate
terraform fmt -recursive
terraform plan
terraform apply
Common Mistakes to avoid
- Keeping all resources in a sinle file.
- Mixing unrelated services in the same file.
- Using unclear or inconsistent file names.
- Not documenting how the project is structured.
- Creating overly complex folder structures for small projects.
Connect With Me
If you enjoyed this post or want to follow my #30DaysOfAWSTerraformChallenge journey, feel free to connect with me here:
💼 LinkedIn: Amit Kushwaha
🐙 GitHub: Amit Kushwaha
📝 Hashnode / Amit Kushwaha
🐦 Twitter/X: Amit Kushwaha
Top comments (0)