Introduction
In computing, two well-known challenges are cache invalidation and naming conventions. This article addresses the latter, specifically focusing on structuring Terraform codebases. Proper organization of Terraform code is crucial for maintaining scalable and manageable infrastructure.

How to get a secure and compliant infrastructure through code?
This paper is for IT Managers, DevOps & Cloud engineers, and software architects involved in infrastructure management and deployment.
For a customer we are currently working on a seven-year-old Terraform codebase managing infrastructure with around 400 instances, including databases, EC2 instances, Kubernetes nodes, and the surrounding infrastructure. This experience reveals numerous issues that make the codebase fragile and difficult to refactor.
Terraform offers a relatively simple interface with HashiCorp Configuration Language (HCL), which works well for straightforward use cases. However, as a codebase expands, tightly coupled dependencies can emerge, making refactoring time-consuming and error-prone.
Practical Advice for Code Organization
Direction of Abstraction
A crucial decision in structuring Terraform codebases is the direction of abstraction: should resources be grouped by type (e.g., all databases, domain names, instances) or by application (e.g., a database, its related domain name, and instance within a single stack)?
Initially, grouping by resource type seems to simplify maintenance. For instance, updating databases involves applying changes to the database project only. This approach is effective initially but leads to organizational challenges as the project grows. Different applications have varied update schedules, and teams may not synchronize their updates. Locking the state of all databases across applications becomes cumbersome. While Terraform’s “targeted” applies can address this, manual coupling management introduces errors, such as inadvertently applying changes to unrelated resources.
An alternative approach is to group resources by application into a single state file. This method reduces the risk of cross-application dependencies and simplifies updates.
Extent of Module Usage
Another key consideration is the extent of module usage. Modules in Terraform are self-contained packages of Terraform configurations that are managed as a group. Initially, minimal module use aims to keep the code simple and avoid unnecessary abstraction. This results in code duplication when setting up new stacks. The subsequent errors and redundancy lead to adopting a single module at the top level.
A Proof of Concept (POC) for a new application demonstrates the effectiveness of this approach. However, refactoring existing applications proves challenging, requiring extensive use of terraform state mv xxx yyy. Although moved {} blocks now simplify this process, significant effort is still needed to write the module and relocate each resource. Maintaining these moved {} blocks is essential, as missing one can disrupt the stack.
Examples and Challenges
During a refactoring process, challenges such as identifying and moving interdependent resources are significant. Tools like terraform plan and terraform state list are invaluable in visualizing the current state and planning the changes.
For example, when consolidating multiple state files into application-specific stacks, careful planning and testing in a staging environment helped mitigate risks. Automating state file migrations and implementing robust CI/CD pipelines also streamlined the process.
Conclusion
By following these guidelines, managing and refactoring Terraform codebases becomes more manageable, leading to more stable and maintainable infrastructure configurations.
- Group state files by application rather than resource type to reduce complexity and synchronization issues.
- Consider early abstraction to prevent code duplication and ease future refactoring efforts.
- Explore other Infrastructure as Code (IaC) options, such as Pulumi, to determine if they better suit your needs.
For those interested in diving deeper, exploring Terraform documentation and community best practices is highly recommended. Reflect on your own Terraform codebase and consider implementing these practices to improve your infrastructure management.