Terraform is the tool of choice for managing cloud infrastructure as code. Whether you’re deploying simple test environments or building enterprise-scale architectures in Azure, one key question always arises:
Should you use a Terraform module, or just stick to resource blocks?
Making the right choice early can save you hours of maintenance, boost reusability, and make your deployments more reliable. In this post, I’ll walk you through the difference, offer practical Azure examples, and share some real-world decision-making tips.
Understanding the Basics
Before diving in, let’s clarify the two concepts:
-
Resource Blocks: The basic building blocks in Terraform. A resource block defines a single piece of infrastructure, such as an Azure Storage Account or a Virtual Network.
-
Modules: Groups of resources (and their configurations) packaged together. Modules can be reused across projects, teams, or environments—much like a function in programming.
When Should You Use a Terraform Module?
Modules are the backbone of large, maintainable Terraform projects. But they aren’t just for enterprises. Here are the most practical situations for using modules in your Azure deployments:
1. Repetition and Reusability
If you find yourself copying the same group of resources across multiple environments—such as dev, test, and prod—it’s a clear sign you need a module.
Example:
-
Azure Key Vault with Private Endpoints
Key Vaults almost always need private endpoints in production. The configuration is non-trivial: subnet IDs, DNS settings, access policies, diagnostic logs. Instead of copying this logic everywhere, you wrap it in a module. Now, you can deploy consistent Key Vaults with a single line.
2. Complexity Management
Complex services often involve many interdependent resources and variables. Wrapping them into a module reduces clutter in your main Terraform files and centralises logic.
Example:
-
Azure Storage Account with Private Endpoints
These require multiple resources: storage account, private endpoint, network interface, DNS configuration, and potentially access control. Encapsulating all of this in a module makes your code cleaner, safer, and easier to maintain.
3. Enforcing Standards and Security
Modules allow you to enforce naming conventions, tagging, monitoring, and security settings company-wide.
Example:
-
You want all VNets or Storage Accounts in your organisation to use certain tags or diagnostic settings. A module can bake in these requirements and prevent accidental omissions.
4. Team Collaboration
Teams can develop, test, and version modules independently. This improves code quality and enables shared infrastructure patterns.
Example:
-
Your cloud engineering team builds a battle-tested “SQL Database with Firewall” module. Application teams simply call the module without worrying about underlying complexities.
When to Use Terraform Resource Blocks
Resource blocks are perfect for:
1. Simplicity and One-Off Deployments
If you only need to deploy something once or twice, and the configuration is straightforward, there’s no need for the overhead of a module.
Example:
-
Azure App Service Plan
Creating a simple App Service Plan with default settings, perhaps for a quick test or internal app. A single resource block does the job—no module required.
2. Prototyping and Learning
When you’re just starting with Terraform or experimenting with new services, resource blocks offer transparency and keep things simple.
3. Highly Custom or Unique Resources
If your use case is so unique that abstraction would actually obscure important details, stick with resource blocks.
How to Decide: A Practical Checklist
Here’s a quick cheat sheet to help you choose:
Scenario | Use Module? | Use Resource Block? |
---|---|---|
You’ll deploy it in more than one place (env, team, project) | ✔️ | |
It’s complex (multi-resource, many variables, security) | ✔️ | |
You need to enforce org-wide standards | ✔️ | |
It’s a one-off, quick, simple resource | ✔️ | |
You’re learning or prototyping | ✔️ | |
Highly unique, unlikely to ever reuse | ✔️ |
Real-World Azure Examples
Scenario | Module? | Resource Block? | Why? |
---|---|---|---|
Key Vault with private endpoints | ✔️ | Reused config, complex, needs consistent security | |
Storage Account with private endpoints | ✔️ | Multi-step setup, reused everywhere | |
App Service Plan for a test app | ✔️ | Simple, one-off, minimal settings | |
Azure Resource Group creation | ✔️ | Basic, almost never worth wrapping in a module | |
VNet with multiple subnets, diagnostics | ✔️ | Standards, complexity, and repeat use |
Best Practices and Pro Tips
-
Start simple: Don’t over-engineer. Not everything needs to be a module.
-
Refactor as you grow: Begin with resource blocks. If you notice repetition or rising complexity, refactor into a module.
-
Version your modules: Use version control for shared modules to avoid “breaking changes” chaos.
-
Document everything: Good module documentation is gold for teams and your future self.
-
Keep modules focused: Each module should solve one clear problem. Avoid “mega-modules” that try to do everything.
Resource block example:
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "example" {
name = "example-resources"
location = "West Europe"
}
resource "azurerm_service_plan" "example" {
name = "example"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
os_type = "Linux"
sku_name = "P1v2"
}
Conclusion: Make the Right Choice for Long-Term Success
Choosing between Terraform modules and resource blocks isn’t just about code structure—it impacts collaboration, security, and scalability.
Use modules for anything you expect to reuse, anything complex, or anything that requires consistency. Stick to resource blocks for small, unique, or experimental needs.
Pro Tip:
Always test your pipeline to ensure you can recreate everything from scratch, and make sure all resources are defined as code. This is the foundation of reliable, auditable, and maintainable infrastructure in Azure (or any cloud).