OpsCanary
Back to daily brief
terraformmodulesPractitioner

Mastering Module Composition in Terraform

5 min read HashiCorp DocsApr 22, 2026
PractitionerHands-on experience recommended

Module composition exists to solve the complexity of managing infrastructure as code. It allows you to take multiple composable building-block modules and assemble them together to produce a larger system. This flat style of module usage simplifies the management of dependencies and improves the overall flexibility of your Terraform configurations.

In practice, you start with a root module and create a flat set of resources, using Terraform's expression syntax to define relationships between them. When you introduce module blocks, your configuration becomes hierarchical. However, it's best to keep the module tree flat, with only one level of child modules. For example, you might define a network module and a Consul cluster module like this:

terraform
1module "network" {
2  source = "./modules/aws-network"
3  base_cidr_block = "10.0.0.0/8"
4}
5module "consul_cluster" {
6  source = "./modules/aws-consul-cluster"
7  vpc_id = module.network.vpc_id
8  subnet_ids = module.network.subnet_ids
9}

In production, remember that implicit assumptions and guarantees define what data a module expects and what it produces. This means you need to be clear about your input variables, like ami for disk images or recordsets for DNS records. Keep an eye on potential pitfalls, such as tightly coupling your modules, which can hinder future refactoring. The official docs don't call out specific anti-patterns here. Use your judgment based on your scale and requirements.

Key takeaways

  • Utilize module composition to create a scalable infrastructure system.
  • Keep your module tree flat with only one level of child modules for simplicity.
  • Define clear assumptions and guarantees for your modules to avoid confusion.
  • Use Terraform's expression syntax to describe relationships between resources effectively.
  • Be cautious of tightly coupling modules, as it can complicate future refactoring.

Why it matters

In production, effective module composition can significantly reduce the complexity of your Terraform configurations, making them easier to manage and scale. This leads to faster deployments and less technical debt over time.

Code examples

terraform
module "network" { source = "./modules/aws-network" base_cidr_block = "10.0.0.0/8" }
terraform
module "consul_cluster" { source = "./modules/aws-consul-cluster" vpc_id = module.network.vpc_id subnet_ids = module.network.subnet_ids }
terraform
variable "ami" { type = object({ id = string architecture = string }) }

When NOT to use this

The official docs don't call out specific anti-patterns here. Use your judgment based on your scale and requirements.

Want the complete reference?

Read official docs

Test what you just learned

Quiz questions written from this article

Take the quiz →

Get the daily digest

One email. 5 articles. Every morning.

No spam. Unsubscribe anytime.