Terraform Registry Tutorial: Build and Publish Reusable Modules

IT Training

YOUR COSMETIC CARE STARTS HERE

Find the Best Cosmetic Hospitals

Trusted • Curated • Easy

Looking for the right place for a cosmetic procedure? Explore top cosmetic hospitals in one place and choose with confidence.

“Small steps lead to big changes — today is a perfect day to begin.”

Explore Cosmetic Hospitals Compare hospitals, services & options quickly.

✓ Shortlist providers • ✓ Review options • ✓ Take the next step with confidence

This article is based on original reporting from searchitoperations.techtarget.com. Some procedural details have been expanded for clarity.

Why Module Reuse Matters in Terraform

Software engineering has long promoted code reuse through reusable artifacts — libraries, packages, and modules. Most ecosystems provide a centralized registry for discovering and sharing these components: Python has the Python Package Index (PyPI), Node.js has npm, and PowerShell has the PowerShell Gallery.

Terraform follows the same pattern. The Terraform Registry is a centralized hub for distributing reusable Terraform modules — self-contained configuration packages that encapsulate a set of related infrastructure resources. Instead of writing the same resource definitions repeatedly across projects, teams can author a module once, publish it, and reference it wherever needed.

Public Registry vs. Private Registry

The Terraform Registry ships in two forms:

  • Public Registry (registry.terraform.io) — hosts official provider plugins and community-contributed modules. Anyone can browse, use, and publish modules here.
  • Private Registry — available as part of Terraform Cloud and Terraform Enterprise. Organizations use this to share modules internally without exposing them publicly.

This tutorial focuses on the public registry: how to create a module, meet the publishing requirements, and make it available for the broader Terraform community.

Prerequisites for Publishing to the Terraform Registry

HashiCorp enforces a set of requirements before a module can be listed in the public registry. Meeting these requirements also encourages good module hygiene that makes your code easier to maintain.

1. Public Version-Controlled Repository

The module must live in a public repository on a supported version control system. At the time of writing, the Terraform Registry supports GitHub, GitLab, Bitbucket, and Azure DevOps repositories. The repository must be publicly accessible so the registry can read its contents.

2. Repository Naming Convention

Repository names must follow this exact format:

terraform-<PROVIDER>-<NAME>Code language: HTML, XML (xml)

Where <PROVIDER> is the provider the module targets (e.g., aws, azurerm, google) and <NAME> describes what the module provisions. The <NAME> segment may contain hyphens. For example:

  • terraform-azurerm-resource-group
  • terraform-aws-vpc
  • terraform-google-cloud-run

3. Repository Description

The repository’s description field (the short blurb on the repository home page) must be populated. The registry surfaces this text in search results, so write a concise, accurate summary of what the module does.

4. Standard Module Structure

HashiCorp defines a standard directory layout that the registry parses to generate documentation and track inputs, outputs, and resources. At a minimum, a module should include:

.
├── main.tf        # Core resource definitions
├── variables.tf   # Input variable declarations
├── outputs.tf     # Output value declarations
└── README.md      # Human-readable documentationCode language: CSS (css)

Larger modules may split logic into sub-modules under a modules/ subdirectory and include example configurations under an examples/ subdirectory. The registry will render these automatically.

5. Semantic Version Tags

The registry identifies releases through Git tags that follow semantic versioning (e.g., v1.0.0, v1.2.3). At least one valid version tag must exist before you can publish. Without a tag, the registry has no release to index.

Step 1 — Create the GitHub Repository

Start by creating a new public repository on GitHub. For an Azure resource group module, name it terraform-azurerm-rg (or a more descriptive variant such as terraform-azurerm-resource-group).

  • Set visibility to Public.
  • Add a README.md to initialize the repo.
  • Add a .gitignore file using the Terraform template (this excludes .terraform/ directories and state files).
  • Choose a license — MIT is common for open-source Terraform modules.
  • Fill in the repository description field before clicking Create.

Step 2 — Clone the Repository and Add Module Files

Clone the new repository to your local workstation and open it in your editor of choice (VS Code works well with the HashiCorp Terraform extension).

git clone https://github.com/<your-org>/terraform-azurerm-rg.git
cd terraform-azurerm-rgCode language: PHP (php)

Create the three core files:

main.tf

resource "azurerm_resource_group" "this" {
  name     = var.name
  location = var.location

  tags = var.tags
}Code language: JavaScript (javascript)

variables.tf

variable "name" {
  description = "The name of the Azure resource group."
  type        = string
}

variable "location" {
  description = "The Azure region in which to create the resource group."
  type        = string
}

variable "tags" {
  description = "A map of tags to apply to the resource group."
  type        = map(string)
  default     = {}
}Code language: JavaScript (javascript)

outputs.tf

output "id" {
  description = "The ID of the resource group."
  value       = azurerm_resource_group.this.id
}

output "name" {
  description = "The name of the resource group."
  value       = azurerm_resource_group.this.name
}

output "location" {
  description = "The location of the resource group."
  value       = azurerm_resource_group.this.location
}Code language: JavaScript (javascript)

Step 3 — Test the Module Locally

Before publishing, validate that the module actually works by referencing it from a local Terraform configuration. Create a separate directory (outside the module repo) for your test configuration:

# File: ../test-rg/main.tf

module "resource_group" {
  source   = "../terraform-azurerm-rg"
  name     = "my-test-rg"
  location = "eastus"
  tags = {
    environment = "dev"
  }
}Code language: PHP (php)

Run the following commands from the test directory:

terraform init
terraform plan

A clean plan output confirms the module is structured correctly. Run terraform apply (with valid Azure credentials configured) to do a full end-to-end test against a real Azure subscription.

Step 4 — Commit, Tag, and Push

Return to the module repository directory, commit all files, and push them to GitHub:

git add .
git commit -m "Initial module release"
git push origin mainCode language: JavaScript (javascript)

Now create and push a semantic version tag. The v prefix is required by the Terraform Registry:

git tag v1.0.0
git push origin v1.0.0Code language: CSS (css)

Without at least one tag, the registry will not index your module releases.

Step 5 — Publish to the Public Terraform Registry

Publishing a module is a one-time action per repository. The steps below only need to be performed once; subsequent releases are picked up automatically when you push new version tags.

  1. Sign in to registry.terraform.io using your GitHub account.
  2. Click Publish in the top navigation bar, then select Module.
  3. The registry will list the public GitHub repositories in your account that match the terraform-<PROVIDER>-<NAME> naming pattern. Select your repository.
  4. Agree to the publishing terms and click Publish Module.
  5. The registry will scan the repository, parse the module structure, and index the version tag. Within a few minutes, the module will appear at a URL similar to registry.terraform.io/modules/<namespace>/rg/azurerm.

From this point forward, any new vX.Y.Z tag you push to the GitHub repository will automatically appear as a new release in the registry — no additional publishing steps required.

Consuming the Published Module

Once published, any Terraform user can consume the module by specifying the registry source:

module "resource_group" {
  source  = "<namespace>/rg/azurerm"
  version = "1.0.0"

  name     = "prod-rg"
  location = "westeurope"
  tags = {
    environment = "production"
  }
}Code language: JavaScript (javascript)

The registry page for the module will display auto-generated documentation for all inputs, outputs, and resources — pulled directly from the variable and output descriptions in your variables.tf and outputs.tf files. Writing good descriptions in those files is therefore essential.

Best Practices for Terraform Module Authoring

  • Pin provider versions in a versions.tf file inside the module to signal which provider versions the module has been tested against.
  • Write descriptive variable and output descriptions — the registry renders these as documentation.
  • Include an examples/ directory with at least one working example configuration. The registry surfaces examples on the module page.
  • Use semantic versioning meaningfully: increment patch versions for bug fixes, minor versions for backwards-compatible additions, and major versions for breaking changes.
  • Add a CHANGELOG.md to help consumers understand what changed between versions.
  • Validate with terraform validate and lint with tflint as part of your CI pipeline before tagging a release.

Summary

Publishing a module to the Terraform Registry requires a properly named public GitHub repository, a standard module file structure, a populated repository description, and at least one semantic version tag. Once these prerequisites are met, the actual publishing step is a one-time operation through the registry UI. All subsequent releases are handled automatically via Git tags, making ongoing module maintenance straightforward for your team and your consumers.

0 0 votes
Article Rating
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
0
Would love your thoughts, please comment.x