Terraform is a powerful tool for managing infrastructure as code, but how you organize your configurations can make or break your project’s scalability, maintainability, and team collaboration. At the core of this organization are config roots—the directories where your Terraform configurations live.
In this blog, we’ll break down 10 proven Terraform config root setups, each tailored to different use cases. Whether you're managing a simple project or complex, multi-cloud infrastructure, you’ll find strategies to optimize your setup. We’ll cover:
- Single Environment, Single Config Root – Simple setup for small projects
- Multi-Environment with Separate State Files – Isolate dev/prod safely
- Shared Modules Across Environments – Maximize code reuse
- Multi-Region & Multi-Cloud Setups – Handle global deployments with ease
- Microservices & SaaS Infrastructure – Organize by service or tenant
- ...and more
For each setup, we’ll provide an example structure, plus the pros and cons to help you choose the right approach. Let’s dive in.
1. Single Environment, Single Config Root (No-Envs Setup)
Use Case: Small projects where all infrastructure is managed in a single environment.
Structure
📂 repo-root/
├── 📂 terraform/
│ ├── main.tf
│ ├── variables.tf
│ ├── outputs.tf
│ ├── terraform.tfvars
Key Points
- terraform/: Houses all configuration files.
- main.tf: Defines infrastructure resources.
- terraform.tfvars: Stores variable values for deployment.
Pros
- Simple and easy to manage - Ideal for small teams or projects with minimal infrastructure.
- Quick setup - No need for complex environment separation or additional tooling.
- Easier state management - Single state file means fewer complexities.
Cons
- Lacks environment isolation - Risky for production since changes impact everything.
- Limited scalability - Becomes harder to manage as the infrastructure grows.
- No rollback per environment - If something breaks, the entire infrastructure is affected.
2. Multi-Environment Setup with Separate State Files
Use Case: Separate environments with isolated configurations and state files.
Structure
📂 repo-root/
├── 📂 terraform/
│ ├── 📂 dev/
│ │ ├── main.tf
│ │ ├── terraform.tfvars
│ ├── 📂 prod/
│ │ ├── main.tf
│ │ ├── terraform.tfvars
Key Points
- dev/prod/: Isolated environments for safer changes.
- terraform.tfvars: Environment-specific variables.
- main.tf: Infrastructure code separated per environment.
Pros
- Better environment isolation - Dev, staging, and prod can be managed separately.
- Safer changes - Reduces the risk of breaking production when deploying new changes.
- More flexible deployments - Different environments can evolve independently.
Cons
- Increased complexity - Managing multiple state files requires extra organization.
- Duplication risk - Without shared modules, repeated configurations across environments.
- Potential for drift - Environments may become inconsistent if not maintained properly.
3. Multi-Environment Setup with Shared Modules
Use Case: Teams reusing modules across multiple environments.
Structure
📂 repo-root/
├── 📂 modules/
│ ├── 📂 network/
│ ├── 📂 compute/
├── 📂 envs/
│ ├── 📂 dev/
│ │ ├── main.tf (calls `modules/network`)
│ │ ├── terraform.tfvars
│ ├── 📂 prod/
│ │ ├── main.tf
│ │ ├── terraform.tfvars
Key Points
- modules/: Central location for reusable code.
- envs/: Environment-specific configurations using shared modules.
- terraform.tfvars: Custom variables for each environment.
Pros
- Code reuse - Reduces duplication by using the same modules for different environments.
- Consistent infrastructure - Ensures environments follow the same configuration patterns.
- Easier updates - Changes to modules propagate across all environments.
Cons
- More complex updates - Module changes must be carefully tested across all environments.
- Versioning challenges - Managing module versions across environments can be tricky.
- Dependency risks - Shared modules may introduce unintended changes across environments.
4. Multi-Region Setup
Use Case: Organizations deploying infrastructure across multiple AWS/GCP/Azure regions.
Structure
📂 repo-root/
├── 📂 terraform/
│ ├── 📂 us-east-1/
│ │ ├── main.tf
│ │ ├── terraform.tfvars
│ ├── 📂 us-west-2/
│ │ ├── main.tf
│ │ ├── terraform.tfvars
Key Points
- us-east-1/us-west-2/: Region-specific directories.
- terraform.tfvars: Region-specific configurations.
- main.tf: Infrastructure definitions tailored to each region.
Pros
- Improved redundancy - Increases availability by deploying infrastructure in multiple regions.
- Optimized performance - Reduces latency for users in different geographic locations.
- Resiliency against outages - Protects against region-specific failures.
Cons
- Higher cost - Running infrastructure in multiple regions increases expenses.
- More operational overhead - Requires additional monitoring, logging, and failover strategies.
- Complex networking - Cross-region networking, DNS, and traffic routing need careful design.
5. Microservices-Based Config Root
Use Case: Teams managing infrastructure per microservice.
Structure
📂 repo-root/
├── 📂 services/
│ ├── 📂 frontend/
│ │ ├── main.tf
│ │ ├── terraform.tfvars
│ ├── 📂 backend/
│ │ ├── main.tf
│ │ ├── terraform.tfvars
Key Points
- services/: Separate directories for each microservice.
- main.tf: Microservice-specific infrastructure definitions.
- terraform.tfvars: Service-specific variable configurations.
Pros
- Scalability - Each microservice can be deployed and managed independently.
- Improved modularity - Changes to one service don’t impact others.
- Better team autonomy - Different teams can own different microservices.
Cons
- State management complexity - Requires careful coordination between microservices.
- Service dependencies - Managing dependencies between services can be difficult.
- More repositories to manage - Increases the number of Terraform configurations to maintain.
6. Multi-Tenant SaaS Infrastructure
Use Case: SaaS platform managing separate infrastructure per tenant.
Structure
📂 repo-root/
├── 📂 tenants/
│ ├── 📂 customerA/
│ │ ├── main.tf
│ │ ├── terraform.tfvars
│ ├── 📂 customerB/
│ │ ├── main.tf
│ │ ├── terraform.tfvars
Key Points
- tenants/: Directories per customer for tenant isolation.
- main.tf: Tenant-specific infrastructure definitions.
- terraform.tfvars: Custom variables per tenant.
Pros
- Stronger tenant isolation - Each tenant has its own infrastructure, reducing security risks.
- Customizable per-tenant configurations - Allows flexibility for different customer needs.
- Scalability - Can add new tenants easily without affecting existing ones.
Cons
- Higher infrastructure cost - Separate environments for each tenant can be expensive.
- Operational complexity - Managing multiple tenants adds overhead.
- State explosion - Handling separate state files for many tenants can become challenging.
7. Monorepo with Multiple Services
Use Case: Ideal for organizations managing several microservices or infrastructure components within a single repository. This structure allows centralized management while maintaining service-specific configurations.
Structure
📂 repo-root/
├── 📂 modules/
│ ├── network/
│ ├── compute/
│ └── database/
├── 📂 services/
│ ├── service-a/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── outputs.tf
│ │ └── backend.tf
│ ├── service-b/
│ └── service-c/
├── 📂 environments/
│ ├── dev/
│ ├── staging/
│ └── prod/
Key Points
- modules/: Central location for reusable code.
- services/: Each service has isolated configurations.
- environments/: Environment-specific overrides and backend configurations.
Pros
- Centralized version control - All infrastructure code lives in a single repository.
- Simplified CI/CD pipelines - Easier to implement workflows for testing and deployment.
- Shared governance - Teams can enforce standards across all services.
Cons
- Repository bloat - Large monorepos can become slow and difficult to manage.
- Coordination overhead - Teams working in the same repo need strong collaboration practices.
- Complex permissions - Managing access control across different services can be tricky.
8. Feature Branch-Based Deployments
Use Case: Best for teams practicing continuous integration/deployment (CI/CD), allowing rapid testing and deployment of feature branches.
Structure
📂 repo-root/
├── 📂 modules/
│ └── common/
├── 📂 environments/
│ ├── dev/
│ ├── staging/
│ └── prod/
├── 📂 features/
│ ├── feature-xyz/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── backend.tf
│ └── feature-abc/
Key Points
- features/: Isolated configurations for each feature.
- CI/CD Integration: Automate deployments using branch names to target specific environments.
- Rollback Ready: Simplified rollback by reverting to previous branches.
Pros
- Safe experimentation - Developers can test infrastructure changes in isolated environments.
- Parallel development - Multiple features can be worked on simultaneously.
- Quick rollbacks - Feature branches can be deleted if something goes wrong.
Cons
- High resource usage - Spinning up environments per branch can be costly.
- Longer CI/CD times - More environments mean longer infrastructure provisioning cycles.
- State file management complexity - Requires careful handling of temporary state files.
9. Multi-Cloud Config Root
Use Case: Managing AWS and GCP infrastructure in separate directories.
Structure
📂 repo-root/
├── 📂 aws/
│ ├── main.tf
│ ├── terraform.tfvars
├── 📂 gcp/
│ ├── main.tf
│ ├── terraform.tfvars
Key Points
- aws/gcp/: Directories for each cloud provider, ensuring clear separation.
- main.tf: Defines cloud-specific infrastructure.
- terraform.tfvars: Stores provider-specific variable configurations.
Pros
- Avoids vendor lock-in - Deploy infrastructure across AWS, GCP, and Azure.
- Resilience and flexibility - Can distribute workloads across different cloud providers.
- Cost optimization - Choose the best cloud provider for each workload.
Cons
- Higher complexity - Requires knowledge of multiple cloud platforms.
- Inconsistent APIs - Each cloud provider has its own tools, policies, and configurations.
- Challenging networking - Inter-cloud communication and security need careful planning.
10. Team-Based Config Root Organization
Use Case: Suitable for large organizations with multiple teams managing different parts of the infrastructure independently.
Structure
📂 repo-root/
├── 📂 modules/
├── 📂 teams/
│ ├── 📂 platform-team/
│ │ ├── networking/
│ │ ├── security/
│ │ └── storage/
│ ├── 📂 devops-team/
│ │ ├── ci-cd/
│ │ └── monitoring/
│ └── 📂 app-team/
│ ├── frontend/
│ └── backend/
├── 📂 environments/
│ ├── dev/
│ ├── staging/
│ └── prod/
Key Points
- teams/: Each team has ownership over its specific configurations.
- modules/: Promote code reuse while maintaining team autonomy.
- Collaboration: Encourages clear boundaries and responsibilities across teams.
Pros
- Clear ownership - Each team is responsible for its own infrastructure.
- Scalability - Teams can work independently without stepping on each other.
- Security and governance - Easier to enforce role-based access control.
Cons
- Potential duplication - Teams may replicate configurations instead of reusing modules.
- Collaboration challenges - Requires strong communication between teams.
- Difficult cross-team dependencies - Coordinating infrastructure that spans multiple teams can be complex.
Final Thoughts
Choosing the right Terraform config root setup is key to managing infrastructure efficiently. Whether you're running a small project, juggling multiple environments, or scaling a multi-tenant SaaS platform, these 10 setups offer a solid foundation for structuring your Terraform repositories effectively.
In Part 2, we’ll dive into example resourcely.yaml
files tailored for each config root setup.
Ready to simplify and automate your Terraform workflows?
Try Resourcely today with a free account and take the guesswork out of Terraform best practices!