Design Variables for Composable Terraform Modules

Learn patterns for designing Terraform module interfaces with required vs optional variables, sensible defaults, and object-typed inputs.

Advanced Patterns

Detailed Explanation

Module Composition Variable Patterns

Well-designed module variables make the difference between a module that's easy to use and one that's a maintenance burden. Follow these patterns for clean, composable module interfaces.

Pattern 1: Required vs. Optional

# Required — no default, caller must provide
variable "project_name" {
  type        = string
  description = "Name of the project (required)"
}

# Optional — has a sensible default
variable "log_retention_days" {
  type        = number
  description = "CloudWatch log retention in days"
  default     = 14
}

Pattern 2: Feature Toggles

variable "enable_monitoring" {
  type        = bool
  description = "Enable CloudWatch monitoring and alarms"
  default     = true
}

variable "enable_backup" {
  type        = bool
  description = "Enable automated backups"
  default     = false
}

Pattern 3: Configuration Objects with Optional Fields

variable "monitoring_config" {
  type = object({
    enabled         = bool
    alarm_email     = optional(string)
    retention_days  = optional(number, 30)
    detail_level    = optional(string, "basic")
  })
  description = "Monitoring configuration"
  default = {
    enabled = true
  }
}

The optional(type, default) syntax (Terraform 1.3+) lets callers omit fields while providing defaults.

Pattern 4: Map of Objects for Multiple Instances

variable "databases" {
  type = map(object({
    engine         = string
    instance_class = string
    storage_gb     = number
    multi_az       = bool
  }))
  description = "Map of database configurations keyed by logical name"
  default     = {}
}

Usage: databases = { main = { engine = "postgres", ... }, analytics = { engine = "mysql", ... } }

Design Principles

  1. Minimize required variables: Every required variable is friction for the caller
  2. Group related settings: Use objects instead of 10 separate variables
  3. Validate early: Catch mistakes at plan time, not apply time
  4. Document defaults: Make it clear what happens when a variable isn't set
  5. Use optional(): Reduce boilerplate for complex objects

Use Case

Teams building shared Terraform module libraries where clean, well-documented variable interfaces reduce friction and errors for module consumers.

Try It — Terraform Variable Generator

Open full tool