cd environments/dev
terraform init
terraform plan -var-file=dev.tfvars
terraform apply -var-file=dev.tfvars
Repeat for staging/prod with their own .tfvars and code.
. 3 environment folders (dev, staging, prod). . Multiple modules (network, compute, loadbalancer, data). . Config for NAT Gateways, route tables for public and private subnets. . Security groups for SSH and load balancer. . IAM roles for instances. . A remote backend to manage state in a safe manner.
You can now expand from here with RDS, ElastiCache, ECS, EKS, etc. by creating more modules or reusing the approach shown above. As you evolve your infrastructure, continue to keep environment differences in .tfvars while reusing the same module code to avoid duplication and keep everything consistent.
This should give you a complete and robust starting point for a multi‐environment, multi‐module Terraform setup. Adjust details (like subnets, NAT strategy, load balancer configs, etc.) as needed for your organization’s requirements!
In each environment folder, you might have a backend.tf that configures the Terraform remote backend. Commonly, teams use S3 with DynamoDB for state locking. For example, environments/dev/backend.tf might look like:
terraform { backend "s3" { bucket = "my-terraform-states" key = "dev/terraform.tfstate" region = "us-east-1" dynamodb_table = "terraform-state-lock" encrypt = true } }
Note: You must create the my-terraform-states S3 bucket and terraform-state-lock DynamoDB table ahead of time (or with another Terraform stack). Then, each environment (dev/staging/prod) would have a different key = "...tfstate" path.
. Keep “modules” stateless and reusable. They should define resources in a generic way, purely parameterized by variables.
. Use environment folders as the “glue.” They set environment‐specific variables and orchestrate how modules fit together (e.g., using the VPC output in the compute module).
. Use .tfvars files to store environment‐specific values (like subnets, CIDRs, etc.). That way you can keep your main code consistent and just change the .tfvars for each environment.
. Outputs let you chain modules together (e.g., pass vpc_id to your compute module).
. Version control your code in Git. Often teams keep all modules and environments in one repo; or they may have a separate repo for modules. Do what best fits your team.
. State management: Consider using a remote backend (e.g., S3 + DynamoDB) so your team can share Terraform state safely for each environment.