5.1.2. The Terraform Registry
💡 First Principle: A registry standardizes module discovery and versioning — modules get a three-part address and published version history — so consuming a community module becomes as predictable as installing a versioned library.
The public Terraform Registry (registry.terraform.io) hosts community and verified modules addressed as <NAMESPACE>/<NAME>/<PROVIDER> — for example terraform-aws-modules/vpc/aws. HCP Terraform and Terraform Enterprise add a private registry for sharing modules within an organization, using an address that includes the registry hostname. To publish a public module, the registry requires a GitHub repository named terraform-<PROVIDER>-<NAME>, the standard module structure (README.md, main.tf, variables.tf and outputs.tf at the root), and semantic-version release tags such as v1.2.0; it then generates documentation from the module's inputs and outputs. The layout is a convention — terraform init loads any directory of .tf files — but it tells every reader where to look: the resources in main.tf, the module's interface in variables.tf and outputs.tf.
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
}
The registry's key advantage over raw Git is the version argument: registry modules are versioned, so you can pin and constrain them with the same operators you use for providers. (Git sources don't support version; you pin them with a ?ref= tag instead.)
⚠️ Exam Trap: The version argument is valid only for registry sources (public or private). For a Git source you pin a specific commit/tag with ?ref=v1.2.0 in the source URL, not with version. Mixing these up is a frequent distractor.
Reflection Question: Why can you use version = "~> 5.0" for a registry module but not for a module sourced directly from GitHub?