Terraform is a widely popular tool used for Infrastructure as Code (IaC) in the cloud world. It supports many cloud providers, including Azure, AWS, Google Cloud, and more. We have been using Terraform for several months to manage the Azure infrastructure (instead of Bicep). In this blog post, we want to share our insights and learnings. This includes the pros and cons of Terraform, as well as some tips and tricks to make the most out of it.

The Good
One of the things we liked about Terraform is its flexibility in configuration. It supports YAML or JSON to define your infrastructure settings, depending on your preference and use case. You can also use Terragrunt, a wrapper for Terraform, to predefine variables and configurations for your modules. This makes your code more reusable and maintainable. Unfortunately, Bicep does not have a wrapper feature yet.
Terraform uses a state file to keep track of the Azure resources and their attributes. This helps to identify any changes or drift between your code and the infrastructure. Bicep also has a similar feature with the --what-if
argument, but it is less sophisticated than Terraform. Especially when you use a subscription scoped deployment with Bicep. The only visible changes will be that of the resource group, not the individual resources.
Terraform also has a lot of built-in functionality and features a small learning curve. It is easy to get started with Terraform and learn its syntax and commands. It also provides a smooth conversion process from other scripting languages, such as Bicep. Moreover, Terraform has some powerful execution options, such as local-exec and remote-exec, that allow you to run additional scripts or commands before, during or after your deployment. It also enables the provisioning of GitHub repository resources, such as GitHub branch protection, webhooks, and environment variables. This can be useful for specific scenarios that require extra automation. Bicep does not have these features yet.
The Bad
However, Terraform is not perfect. It has some drawbacks and challenges that you need to be aware of. Since Terraform is a general-purpose tool that works with many cloud providers, it may not support all the Azure services or functionalities that you need. For example, Terraform does not yet support the latest features for provisioning Azure Container Apps with scaling rules and Dapr Components. You may also encounter some delays or bugs when new Azure resources or features are released. On the other hand, Bicep is explicitly designed for Azure and supports new resources seamlessly.
1 |
<strong><em>TIP! </em></strong><em>To tackle the limited support by Terraform, a workaround is possible: the <a href="https://registry.terraform.io/providers/Azure/azapi/latest/docs" target="_blank" rel="noreferrer noopener">AzApi provider</a>! But beware, Terraform bugs can still sneak u.</em> |
The state file is powerful and crucial tool for Terraform’s operation, but it can also cause major problems if not handled properly. Manual changes made to resources within the Azure portal can easily corrupt the state file, leading to inconsistencies between the desired and deployed infrastructure. Additionally, if a deployment is interrupted or a runner crashes, the state file may not be fully updated. As result causing subsequent runs to fail as the deployed resources may not match the desired state. This could also result in the state file being locked indefinitely and requires manual intervention to release the locks and update the state file.
1 |
<strong><em>TIP!</em></strong><em> Make sure to backup and secure your state file regularly, as losing or corrupting it can cause serious issues.</em> |
Renaming a module can also result in errors during deployment, as Terraform attempts to remove the old-named module along with its resources, potentially causing conflicts. Another limitation is Terraform’s inability to detect resources that were manually provisioned outside of Terraform within the Azure portal. This is not the same for Bicep CLI/ ARM templates, which uses incremental or complete deployment and detected resource changes during runtime.
1 |
<strong><em>TIP!</em></strong><em> It is also important to determine a possible multi-regional deployment. We recommend to use different state files for different regions. If not, this will cause the complete re-creation of the existing resources and in-turn lose all data.</em> |
Debugging large and complex Terraform infrastructures can be challenging, especially when encountering cyclic errors. These errors may occur when there are conflicts in resource names between modules, even if they are not directly dependent on each other. Understanding and resolving these issues can be particularly problematic in extensive Terraform projects. The complexity of such projects can result in unintended modifications in the infrastructure pipeline, making it difficult to maintain and troubleshoot, especially with monolithic deployments of the complete infrastructure. Additionally, the presence of similar data blocks can cause resource recreations or unintended changes, even when no deliberate modifications were made.
1 |
<strong><em>TIP!</em></strong><em> To achieve a more organized deployment, consider splitting it into modular deployments within different environments. Only apply it for resources that do not directly depend on each other. However, avoid splitting the deployment if one resource is modified by different deployments. This will help maintain the coherence and efficiency of the deployment process.</em> |
Lastly, developers using Terraform (mainly with a Bicep/ARM template background) may find it confusing that changes or deployments are not visible within the Azure portal’s Deployment tab. This lack of visibility can hinder the debugging and monitoring process. Bicep on the other hands does provide visibility of the deployments within the Azure portal.
Conclusion
Overall, Terraform is a powerful tool for managing infrastructure as code for a variety of cloud providers. It offers a flexible configuration format and the ability to modularize code for increased reuse and flexibility. Additionally, Terraform integrates with many popular cloud providers, including Azure, AWS, Google Cloud and GitHub.
Utilize Terraform when dealing with complex and modular provisioning and automation of deployments. Terraform offers a high amount of built-in functionalities for pre-deployment, during deployment, and post-deployment stages. As result this enables easy modulation of resources. If your deployment necessitates predefined variables and configurations for modules, it is highly recommended to employ Terragrunt in conjunction with Terraform. This approach eliminates the need for scripting and creating additional code. Including seamless integration of additional scripts or commands before or after your deployments.
Utilize Bicep for managing less complex resources that can be released incrementally and easily adjusted using the Azure Portal. When there is a need for support of the latest generally available features, Bicep is the go-to tool. It ensures that you have access to the most up-to-date capabilities provided by Azure, enabling you to leverage the full potential of the platform.