Designing and Evolving Modules

Scenario: A module rename causes every consumer to replace production resources despite no remote attribute changing.

Module quality includes typed variables, descriptions, validation, precise outputs, version constraints, examples, documentation, formatting, validation, tests, and upgrade guidance. Maintain backward compatibility within a major line. Use moved blocks when internal addresses change and deprecate inputs before removal. Preconditions and postconditions can protect assumptions that types alone cannot express.

Analogy: A reusable module is an internal platform API. Its resource labels are database keys: changing them requires a migration, not just a rename.

A worked configuration

variable "environment" {
  type = string
  validation {
    condition     = contains(["dev", "stage", "prod"], var.environment)
    error_message = "environment must be dev, stage, or prod."
  }
}

Test both fresh creation and upgrade from the previous released version. A module that passes only greenfield tests can still destroy resources during a consumer upgrade.

Note: Treat the plan as a change contract: understand every create, update, replacement, and destroy before approving it.
Goal: Reinforce this lesson in the tf-moved-refactor Terraform lab. Open /labs/terraform and choose slug tf-moved-refactor; the lab runs real Terraform against the offline FakeCloud provider.