Learn industry best practices for organizing your Terraform code with a clear and efficient subfolder structure for managing multiple environments and components.
This article outlines a structured approach to organizing your Terraform projects for better maintainability and scalability. We'll establish a clear directory structure that separates concerns like environments, reusable modules, and deployment stages. This approach promotes code reusability, simplifies environment management, and enhances collaboration in infrastructure-as-code projects.
Create a directory for your project. Inside, create three more directories: environments
, modules
, and stages
.
The environments
directory will hold configurations for different environments like production
and staging
. Each environment will have its own subdirectory.
The modules
directory will contain reusable Terraform modules. For example, you might have a module for creating a VPC or a module for deploying a specific application.
The stages
directory will hold configurations for different stages of your infrastructure deployment. This could include stages like network
, database
, and application
. Each stage will have its own subdirectory.
Inside each environment directory, create subdirectories for each stage you want to deploy in that environment. For example, the production
environment might have subdirectories for network
, database
, and application
.
Inside each stage directory, create a main.tf
file and any other necessary files for that stage. The main.tf
file will contain the Terraform code to deploy the resources for that stage.
Use Terraform modules to encapsulate reusable infrastructure components. Define your modules in the modules
directory and call them from your stage configurations.
When defining your Terraform code, use relative paths to reference modules and other files within your project. This will make your code more portable and easier to maintain.
Use a consistent naming convention for your files, directories, and Terraform resources. This will make your code easier to read and understand.
Use a remote backend for storing your Terraform state. This will allow you to collaborate with others on your infrastructure code and ensure that your state is stored securely.
Use Terraform workspaces to manage different environments or deployments. This will allow you to keep your code and state separate for each environment.
Use a version control system like Git to track changes to your Terraform code. This will allow you to roll back changes if necessary and collaborate with others on your infrastructure code.
This Terraform code defines infrastructure for different environments (production and staging) using a modular approach. It includes modules for common components like VPCs and leverages remote state storage in S3. The code is structured to promote reusability and maintainability, allowing for consistent deployments across environments.
โโโ environments
โ โโโ production
โ โ โโโ network
โ โ โ โโโ main.tf
โ โ โโโ database
โ โ โ โโโ main.tf
โ โ โโโ application
โ โ โโโ main.tf
โ โโโ staging
โ โโโ network
โ โ โโโ main.tf
โ โโโ database
โ โโโ main.tf
โโโ modules
โ โโโ vpc
โ โ โโโ main.tf
โ โโโ aws_s3_bucket
โ โโโ main.tf
โโโ stages
โโโ network
โ โโโ main.tf
โโโ database
โ โโโ main.tf
โโโ application
โโโ main.tf
environments/production/network/main.tf
# Configure the AWS Provider
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}
provider "aws" {
region = "us-west-2"
}
# Use the VPC module
module "vpc" {
source = "../../../modules/vpc"
vpc_cidr = "10.0.0.0/16"
}
environments/production/database/main.tf
# Configure the AWS Provider
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}
provider "aws" {
region = "us-west-2"
}
# Use the VPC module
module "vpc" {
source = "../../../modules/vpc"
vpc_cidr = "10.0.0.0/16"
}
# Create a security group for the database
resource "aws_security_group" "db_sg" {
name = "database_sg"
vpc_id = module.vpc.vpc_id
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
cidr_blocks = [module.vpc.vpc_cidr]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
modules/vpc/main.tf
# Create a VPC
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "main-vpc"
}
}
# Create a subnet
resource "aws_subnet" "main" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "us-west-2a"
tags = {
Name = "main-subnet"
}
}
# Create an internet gateway
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "main-igw"
}
}
stages/network/main.tf
# Configure the AWS Provider
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
backend "s3"{
bucket = "your-bucket-name"
key = "terraform.tfstate"
region = "us-west-2"
}
}
# Use the VPC module
module "vpc" {
source = "../../modules/vpc"
vpc_cidr = "10.0.0.0/16"
}
Explanation:
vpc
module encapsulates VPC creation logic, making it reusable across environments and stages.../../modules/vpc
) to reference modules, enhancing portability.backend "s3"
configuration enables storing Terraform state in an S3 bucket, facilitating collaboration and state management.terraform workspace select production
) to isolate state and configurations.To use this structure:
vpc_cidr
, AWS region) to match your requirements.terraform init
in each environment's stage directory (e.g., environments/production/network
) to initialize Terraform.terraform apply
to deploy your infrastructure.This structure provides a solid foundation for managing your infrastructure as code with Terraform, promoting modularity, reusability, and maintainability. Remember to adapt it to your specific project needs and best practices.
General:
Environments:
Modules:
Stages:
depends_on
in your Terraform code to ensure resources are created in the correct order.Security:
Best Practices:
Additional Considerations:
This article outlines a best-practice structure for organizing Terraform projects to enhance modularity, maintainability, and collaboration.
Key Directory Structure:
production
, staging
). Each environment has its own subdirectory.network
, database
, application
). Each stage has its own subdirectory.Workflow:
production/network
, staging/database
) to reflect the stages deployed in that environment.main.tf
file and any other necessary files. The main.tf
file contains the Terraform code for deploying resources in that stage.modules
directory to encapsulate reusable infrastructure components. Reference these modules using relative paths within your stage configurations.Best Practices:
By adhering to these principles and adapting the structure to your specific needs, you can establish a robust and scalable foundation for managing your infrastructure with Terraform. This approach not only enhances code organization but also promotes collaboration, simplifies environment management, and ensures the long-term maintainability of your infrastructure-as-code projects.