What Is a Terraform Module Source?
The source argument is the address inside a module block that tells Terraform exactly where to go and fetch the module's code from. It is the only required argument in any module call — without it, Terraform has no idea what you are trying to use.
Think of source like the address line on a delivery — it can point to a folder right next to your code, a published package in a public catalog, or a specific commit in a private company repository. Each format has its own rules for versioning.
At Zerodha, the security team maintains a private Git repository of approved modules — terraform-security-baseline. Every team's root module must source its IAM role module from that one repository and pin it to a tag. This is how the security team enforces that nobody accidentally creates an IAM role with * permissions — the approved module simply does not allow it.
Local Path Source
Used when the module lives inside the same repository as the code calling it. Always starts with ./ or ../:
module "vpc" { source = "./modules/vpc" # relative to the calling .tf file's directory} module "shared_tags" { source = "../../shared-modules/tags" # going up two directories first}Local sources do not support a version argument — there is nothing to version. Whatever is in that folder right now is what gets used.
Terraform Registry Source
The public registry uses a short three-part address: <NAMESPACE>/<NAME>/<PROVIDER>. This is the format you see for community modules like terraform-aws-modules:
module "vpc" { source = "terraform-aws-modules/vpc/aws" # namespace / name / provider version = "~> 5.0" # registry modules SHOULD always pin a version}GitHub / Git Source
For modules hosted directly on GitHub or any Git server, prefix with git:: and the full clone URL. Use ?ref= to pin to a tag, branch, or commit SHA:
module "ecs_service" { source = "git::https://github.com/swiggy-platform/tf-modules.git?ref=v3.1.0" # ^^^^^^^^^^^ # tag, branch, or full commit SHA} # Pulling a module from a SUBDIRECTORY inside a larger repo — use a double slashmodule "vpc" { source = "git::https://github.com/swiggy-platform/tf-modules.git//networking/vpc?ref=v3.1.0" # ^^ subdirectory path after //} # Pinning to a specific commit SHA instead of a tag — useful for maximum reproducibilitymodule "rds" { source = "git::https://github.com/swiggy-platform/tf-modules.git//database?ref=a1b2c3d4"}Tag vs Branch vs Commit — Which Should You Pin To?
INFORMATIONTip from a senior engineer: never, ever point `ref=` at `main` or `master` in a production root module. A teammate can merge a breaking change to that branch at 2pm and your `terraform init -upgrade` at 3pm silently pulls it in.
| Pin Type | Stability | When to Use |
|---|---|---|
Git tag (ref=v2.1.0) |
Highest — tags do not move | Production root modules — always |
Commit SHA (ref=a1b2c3d) |
Highest — exact snapshot | When you need byte-for-byte reproducibility |
Branch (ref=main) |
Lowest — moves underneath you | Only inside the module repo's own CI testing |
Private Registry Source
Terraform Cloud and Terraform Enterprise host private registries with a four-part address that includes your organisation's hostname:
module "payments_vpc" { source = "app.terraform.io/phonepay-org/vpc/aws" # ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ # private registry organisation namespace version = "1.4.2"}SSH Source for Private Git Repos
If your company's Git server requires SSH authentication instead of HTTPS tokens, use the git:: prefix with an SSH URL:
module "internal_module" { source = "git::ssh://git@github.com/cred-platform/tf-modules.git//iam-role?ref=v1.0.0"}This requires your CI runner or laptop to already have an SSH key registered with access to that repository.
Quick Reference
| Source Format | Example | Supports version? |
|---|---|---|
| Local path | ./modules/vpc |
No |
| Public registry | terraform-aws-modules/vpc/aws |
Yes |
| Git (HTTPS) | git::https://github.com/org/repo.git?ref=v1.0.0 |
No — use ref instead |
| Git (SSH) | git::ssh://git@github.com/org/repo.git?ref=v1.0.0 |
No — use ref instead |
| Private registry | app.terraform.io/org/module/provider |
Yes |
| Error | Root Cause | Fix |
|---|---|---|
Error downloading module |
Git URL typo or no network access | Double-check the exact clone URL and your VPN/runner network access |
Module source has changed |
Source string was edited | Run terraform init again — Terraform refuses to proceed silently |
git exited with 128 |
SSH key not authorized for the repo | Add your deploy key or personal key to the Git server |
Could not find module in registry |
Wrong namespace/name/provider order | Re-check the exact three-part address on registry.terraform.io |