--- page_title: Module Sources description: >- The source argument tells Terraform where to find child modules's configurations in locations like GitHub, the Terraform Registry, Bitbucket, Git, Mercurial, S3, and GCS. --- # Module Sources The `source` argument in [a `module` block](/language/modules/syntax) tells Terraform where to find the source code for the desired child module. Terraform uses this during the module installation step of `terraform init` to download the source code to a directory on local disk so that it can be used by other Terraform commands. > **Hands-on:** Try our HashiCorp Learn tutorials to use modules from [the > registry](https://learn.hashicorp.com/tutorials/terraform/module-use) > or [locally](https://learn.hashicorp.com/tutorials/terraform/module-create). The module installer supports installation from a number of different source types, as listed below. - [Local paths](#local-paths) - [Terraform Registry](#terraform-registry) - [GitHub](#github) - [Bitbucket](#bitbucket) - Generic [Git](#generic-git-repository), [Mercurial](#generic-mercurial-repository) repositories - [HTTP URLs](#http-urls) - [S3 buckets](#s3-bucket) - [GCS buckets](#gcs-bucket) - [Modules in Package Sub-directories](#modules-in-package-sub-directories) Each of these is described in the following sections. Module source addresses use a _URL-like_ syntax, but with extensions to support unambiguous selection of sources and additional features. We recommend using local file paths for closely-related modules used primarily for the purpose of factoring out repeated code elements, and using a native Terraform module registry for modules intended to be shared by multiple calling configurations. We support other sources so that you can potentially distribute Terraform modules internally with existing infrastructure. Many of the source types will make use of "ambient" credentials available when Terraform is run, such as from environment variables or credentials files in your home directory. This is covered in more detail in each of the following sections. We recommend placing each module that is intended to be re-usable in the root of its own repository or archive file, but it is also possible to [reference modules from subdirectories](#modules-in-package-sub-directories). ## Local Paths Local path references allow for factoring out portions of a configuration within a single source repository. ```hcl module "consul" { source = "./consul" } ``` A local path must begin with either `./` or `../` to indicate that a local path is intended, to distinguish from [a module registry address](#terraform-registry). Local paths are special in that they are not "installed" in the same sense that other sources are: the files are already present on local disk (possibly as a result of installing a parent module) and so can just be used directly. Their source code is automatically updated if the parent module is upgraded. Note that Terraform does not consider an _absolute_ filesystem path (starting with a slash, a drive letter, or similar) to be a local path. Instead, Terraform will treat that in a similar way as a remote module and copy it into the local module cache. An absolute path is a "package" in the sense described in [Modules in Package Sub-directories](#modules-in-package-sub-directories). We don't recommend using absolute filesystem paths to refer to Terraform modules, because it will tend to couple your configuration to the filesystem layout of a particular computer. ## Terraform Registry A module registry is the native way of distributing Terraform modules for use across multiple configurations, using a Terraform-specific protocol that has full support for module versioning. [Terraform Registry](https://registry.terraform.io/) is an index of modules shared publicly using this protocol. This public registry is the easiest way to get started with Terraform and find modules created by others in the community. You can also use a [private registry](/registry/private), either via the built-in feature from Terraform Cloud, or by running a custom service that implements [the module registry protocol](/registry/api-docs). Modules on the public Terraform Registry can be referenced using a registry source address of the form `//`, with each module's information page on the registry site including the exact address to use. ```hcl module "consul" { source = "hashicorp/consul/aws" version = "0.1.0" } ``` The above example will use the [Consul module for AWS](https://registry.terraform.io/modules/hashicorp/consul/aws) from the public registry. For modules hosted in other registries, prefix the source address with an additional `/` portion, giving the hostname of the private registry: ```hcl module "consul" { source = "app.terraform.io/example-corp/k8s-cluster/azurerm" version = "1.1.0" } ``` If you are using the SaaS version of Terraform Cloud, its private registry hostname is `app.terraform.io`. If you use a self-hosted Terraform Enterprise instance, its private registry hostname is the same as the host where you'd access the web UI and the host you'd use when configuring the [Terraform Cloud CLI integration](/cli/cloud). Registry modules support versioning. You can provide a specific version as shown in the above examples, or use flexible [version constraints](/language/modules/syntax#version). You can learn more about the registry at the [Terraform Registry documentation](/registry/modules/use#using-modules). To access modules from a private registry, you may need to configure an access token [in the CLI config](/cli/config/config-file#credentials). Use the same hostname as used in the module source string. For a private registry within Terraform Cloud, use the same authentication token as you would use with the Enterprise API or command-line clients. ## GitHub Terraform will recognize unprefixed `github.com` URLs and interpret them automatically as Git repository sources. ```hcl module "consul" { source = "github.com/hashicorp/example" } ``` The above address scheme will clone over HTTPS. To clone over SSH, use the following form: ```hcl module "consul" { source = "git@github.com:hashicorp/example.git" } ``` These GitHub schemes are treated as convenient aliases for [the general Git repository address scheme](#generic-git-repository), and so they obtain credentials in the same way and support the `ref` argument for selecting a specific revision. You will need to configure credentials in particular to access private repositories. ## Bitbucket Terraform will recognize unprefixed `bitbucket.org` URLs and interpret them automatically as BitBucket repositories: ```hcl module "consul" { source = "bitbucket.org/hashicorp/terraform-consul-aws" } ``` This shorthand works only for public repositories, because Terraform must access the BitBucket API to learn if the given repository uses Git or Mercurial. Terraform treats the result either as [a Git source](#generic-git-repository) or [a Mercurial source](#generic-mercurial-repository) depending on the repository type. See the sections on each version control type for information on how to configure credentials for private repositories and how to specify a specific revision to install. ## Generic Git Repository Arbitrary Git repositories can be used by prefixing the address with the special `git::` prefix. After this prefix, any valid [Git URL](https://git-scm.com/docs/git-clone#_git_urls) can be specified to select one of the protocols supported by Git. For example, to use HTTPS or SSH: ```hcl module "vpc" { source = "git::https://example.com/vpc.git" } module "storage" { source = "git::ssh://username@example.com/storage.git" } ``` Terraform installs modules from Git repositories by running `git clone`, and so it will respect any local Git configuration set on your system, including credentials. To access a non-public Git repository, configure Git with suitable credentials for that repository. If you use the SSH protocol then any configured SSH keys will be used automatically. This is the most common way to access non-public Git repositories from automated systems because it allows access to private repositories without interactive prompts. If using the HTTP/HTTPS protocol, or any other protocol that uses username/password credentials, configure [Git Credentials Storage](https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage) to select a suitable source of credentials for your environment. If your Terraform configuration will be used within [Terraform Cloud](https://www.hashicorp.com/products/terraform), only SSH key authentication is supported, and [keys can be configured on a per-workspace basis](/cloud-docs/workspaces/settings/ssh-keys). ### Selecting a Revision By default, Terraform will clone and use the default branch (referenced by `HEAD`) in the selected repository. You can override this using the `ref` argument. The value of the `ref` argument can be any reference that would be accepted by the `git checkout` command, such as branch, SHA-1 hash (short or full), or tag names. For a full list of the possible values, see [Git Tools - Revision Selection](https://git-scm.com/book/en/v2/Git-Tools-Revision-Selection#_single_revisions) in [the Git Book](https://git-scm.com/book/en/v2). ```hcl # select a specific tag module "vpc" { source = "git::https://example.com/vpc.git?ref=v1.2.0" } # directly select a commit using its SHA-1 hash module "storage" { source = "git::https://example.com/storage.git?ref=51d462976d84fdea54b47d80dcabbf680badcdb8" } ``` ### Shallow Clone For larger repositories you may prefer to make only a shallow clone in order to reduce the time taken to retrieve the remote repository. The `depth` URL argument corresponds to [the `--depth` argument to `git clone`](https://git-scm.com/docs/git-clone#Documentation/git-clone.txt---depthltdepthgt), telling Git to create a shallow clone with the history truncated to only the specified number of commits. However, because shallow clone requires different Git protocol behavior, setting the `depth` argument makes Terraform pass your [`ref` argument](#selecting-a-revision), if any, to [the `--branch` argument to `git clone`](https://git-scm.com/docs/git-clone#Documentation/git-clone.txt---branchltnamegt) instead. That means it must specify a named branch or tag known to the remote repository, and that raw commit IDs are not acceptable. Because Terraform only uses the most recent selected commit to find the source code of your specified module, it is not typically useful to set `depth` to any value other than `1`. ### "scp-like" address syntax When using Git over SSH, we recommend using the `ssh://`-prefixed URL form for consistency with all of the other URL-like git address forms. You may opt to use the alternative "scp-like" syntax instead, in which case you must omit the `ssh://` scheme part and include only the `git::` part. For example: ```hcl module "storage" { source = "git::username@example.com:storage.git" } ``` If you use the `ssh://` URL scheme then Terraform will assume that the colon marks the beginning of a port number, rather than the beginning of the path. This matches how Git itself interprets these different forms, aside from the Terraform-specific `git::` selector prefix. ## Generic Mercurial Repository You can use arbitrary Mercurial repositories by prefixing the address with the special `hg::` prefix. After this prefix, any valid [Mercurial URL](https://www.mercurial-scm.org/repo/hg/help/urls) can be specified to select one of the protocols supported by Mercurial. ```hcl module "vpc" { source = "hg::http://example.com/vpc.hg" } ``` Terraform installs modules from Mercurial repositories by running `hg clone`, and so it will respect any local Mercurial configuration set on your system, including credentials. To access a non-public repository, configure Mercurial with suitable credentials for that repository. If you use the SSH protocol then any configured SSH keys will be used automatically. This is the most common way to access non-public Mercurial repositories from automated systems because it allows access to private repositories without interactive prompts. If your Terraform configuration will be used within [Terraform Cloud](https://www.hashicorp.com/products/terraform), only SSH key authentication is supported, and [keys can be configured on a per-workspace basis](/cloud-docs/workspaces/settings/ssh-keys). ### Selecting a Revision You can select a non-default branch or tag using the optional `ref` argument: ```hcl module "vpc" { source = "hg::http://example.com/vpc.hg?ref=v1.2.0" } ``` ## HTTP URLs When you use an HTTP or HTTPS URL, Terraform will make a `GET` request to the given URL, which can return _another_ source address. This indirection allows using HTTP URLs as a sort of "vanity redirect" over a more complicated module source address. Terraform will append an additional query string argument `terraform-get=1` to the given URL before sending the `GET` request, allowing the server to optionally return a different result when Terraform is requesting it. If the response is successful (`200`-range status code), Terraform looks in the following locations in order for the next address to access: - The value of a response header field named `X-Terraform-Get`. - If the response is an HTML page, a `meta` element with the name `terraform-get`: ```html ``` In either case, the result is interpreted as another module source address using one of the forms documented elsewhere on this page. If an HTTP/HTTPS URL requires authentication credentials, use a `.netrc` file in your home directory to configure these. For information on this format, see [the documentation for using it in `curl`](https://everything.curl.dev/usingcurl/netrc). ### Fetching archives over HTTP As a special case, if Terraform detects that the URL has a common file extension associated with an archive file format then it will bypass the special `terraform-get=1` redirection described above and instead just use the contents of the referenced archive as the module source code: ```hcl module "vpc" { source = "https://example.com/vpc-module.zip" } ``` The extensions that Terraform recognizes for this special behavior are: - `zip` - `tar.bz2` and `tbz2` - `tar.gz` and `tgz` - `tar.xz` and `txz` If your URL _doesn't_ have one of these extensions but refers to an archive anyway, use the `archive` argument to force this interpretation: ```hcl module "vpc" { source = "https://example.com/vpc-module?archive=zip" } ``` -> **Note:** If the content of the archive file is a directory, you will need to include that directory in the module source. Read the section on [Modules in Package Sub-directories](#modules-in-package-sub-directories) for more information. ## S3 Bucket You can use archives stored in S3 as module sources using the special `s3::` prefix, followed by [an S3 bucket object URL](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingBucket.html). ```hcl module "consul" { source = "s3::https://s3-eu-west-1.amazonaws.com/examplecorp-terraform-modules/vpc.zip" } ``` -> **Note:** Buckets in AWS's us-east-1 region must use the hostname `s3.amazonaws.com` (instead of `s3-us-east-1.amazonaws.com`). The `s3::` prefix causes Terraform to use AWS-style authentication when accessing the given URL. As a result, this scheme may also work for other services that mimic the S3 API, as long as they handle authentication in the same way as AWS. The resulting object must be an archive with one of the same file extensions as for [archives over standard HTTP](#fetching-archives-over-http). Terraform will extract the archive to obtain the module source tree. The module installer looks for AWS credentials in the following locations, preferring those earlier in the list when multiple are available: - The `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables. - The default profile in the `.aws/credentials` file in your home directory. - If running on an EC2 instance, temporary credentials associated with the instance's IAM Instance Profile. ## GCS Bucket You can use archives stored in Google Cloud Storage as module sources using the special `gcs::` prefix, followed by [a GCS bucket object URL](https://cloud.google.com/storage/docs/request-endpoints#typical). For example - `gcs::https://www.googleapis.com/storage/v1/BUCKET_NAME/PATH_TO_MODULE` - `gcs::https://www.googleapis.com/storage/v1/BUCKET_NAME/PATH/TO/module.zip` ```hcl module "consul" { source = "gcs::https://www.googleapis.com/storage/v1/modules/foomodule.zip" } ``` The module installer uses Google Cloud SDK to authenticate with GCS. You can use any of the following methods to set Google Cloud Platform credentials: * Set the `GOOGLE_OAUTH_ACCESS_TOKEN` environment variable to a raw Google Cloud Platform OAuth access token. * Enter the path of your service account key file in the `GOOGLE_APPLICATION_CREDENTIALS` environment variable. * If you're running Terraform from a GCE instance, default credentials are automatically available. See [Creating and Enabling Service Accounts](https://cloud.google.com/compute/docs/access/create-enable-service-accounts-for-instances) for Instances for more details. * On your computer, you can make your Google identity available by running `gcloud auth application-default login`. ## Modules in Package Sub-directories When the source of a module is a version control repository or archive file (generically, a "package"), the module itself may be in a sub-directory relative to the root of the package. A special double-slash syntax is interpreted by Terraform to indicate that the remaining path after that point is a sub-directory within the package. For example: - `hashicorp/consul/aws//modules/consul-cluster` - `git::https://example.com/network.git//modules/vpc` - `https://example.com/network-module.zip//modules/vpc` - `s3::https://s3-eu-west-1.amazonaws.com/examplecorp-terraform-modules/network.zip//modules/vpc` If the source address has arguments, such as the `ref` argument supported for the version control sources, the sub-directory portion must be _before_ those arguments: - `git::https://example.com/network.git//modules/vpc?ref=v1.2.0` - `github.com/hashicorp/example//modules/vpc?ref=v1.2.0` Terraform will still extract the entire package to local disk, but will read the module from the subdirectory. As a result, it is safe for a module in a sub-directory of a package to use [a local path](#local-paths) to another module as long as it is in the _same_ package.