Why Does Terraform path.module Point to the Current Directory Instead of the Module's Directory?

Terraform's path.module always resolves to the absolute filesystem path of the directory containing the module where the expression is evaluated, which means the root module naturally returns your current working directory because that is where the configuration lives on disk.

When working with the hashicorp/terraform codebase, understanding this built-in variable is essential for writing portable infrastructure configurations. The behavior often surprises practitioners who expect path.module to track original source locations, but its design guarantees deterministic file operations by always referencing the actual module copy Terraform is executing.

How path.module Evaluates Module Locations

The path.module variable is a read-only filesystem path that points to the directory containing the .tf files for the module currently being evaluated. This is not a reference to a source URL, version control path, or registry address—it is strictly the absolute path on disk where Terraform has loaded the module.

According to the source code in internal/configs/hcl2modulevars.go, Terraform registers path.module as a built-in variable whose value is populated from the module's loader context. The value comes from module.Path, which represents the absolute directory path assigned during module initialization.

The Root Module and Current Working Directory

When you run terraform init, plan, or apply, Terraform treats the directory you execute the command from as the root module. This is implemented in internal/command/meta.go, where the CLI supplies the working directory to initialize the root module context.

Because the root module is itself a module, the same rules apply: path.module expands to the directory containing the root module's configuration files. Since you are running Terraform from that directory, path.module naturally equals your current working directory.

Child Modules and the .terraform/modules Directory

For child modules—whether sourced from local paths, remote registries, or version control systems—Terraform downloads and materializes the code under the hidden .terraform/modules directory. When an expression inside a child module is evaluated, path.module points to this extracted copy's location, not the original source reference.

The internal/configs/moduleloader.go file handles this process. After downloading a module, the loader sets the module.Path property to the absolute directory of the materialized copy. This design sandboxes file operations, ensuring that functions like file() or templatefile() always read from the exact copy Terraform is using, regardless of where the source code originally lived.

Source Code Implementation Details

Variable Registration in hcl2modulevars.go

In internal/configs/hcl2modulevars.go, Terraform registers path.module as a built-in read-only variable. The registration connects the variable name to the module's directory path stored in the loader context, making it available to all expressions within that module's scope.

Module Path Assignment in moduleloader.go

The internal/configs/moduleloader.go file contains the logic that assigns the physical directory path after module resolution. When Terraform fetches a module from any source, the loader records the absolute path of the resulting directory structure, which later becomes the value of path.module.

CLI Working Directory Handling in meta.go

The internal/command/meta.go file establishes the connection between your shell's current directory and the root module. It initializes the root module using the working directory supplied to the CLI, ensuring that path.module for the root configuration always matches where you ran the command.

Practical Examples

Using path.module in the Root Module

When running Terraform from your project directory, path.module returns that absolute path:


# main.tf (root module)

locals {
  root_dir = path.module
}

output "root_dir" {
  value = local.root_dir
}

Running terraform apply from /home/alice/project outputs:


root_dir = "/home/alice/project"

Child Module Resolution

For modules referenced in your configuration, the path points to the materialized copy:


# modules/example/outputs.tf

output "module_dir" {
  value = path.module
}

# main.tf (root)

module "example" {
  source = "./modules/example"
}

After running terraform apply, the output shows:


module_dir = "/home/alice/project/.terraform/modules/example"

Notice this points to the cached copy under .terraform/modules, not the original source path ./modules/example.

Referencing Files Reliably

Because path.module resolves to the actual module location, you can safely reference relative files:


# modules/example/main.tf

data "template_file" "example" {
  template = file("${path.module}/config.tmpl")
}

This pattern works consistently whether the module is local, downloaded from the Terraform Registry, or pulled from a Git repository.

Summary

  • Terraform path.module always returns the absolute filesystem path of the directory containing the module being evaluated.
  • For root modules, this equals the current working directory where you run Terraform commands, as implemented in internal/command/meta.go.
  • For child modules, this points to the materialized copy under .terraform/modules/ rather than the original source location.
  • The behavior is controlled by internal/configs/moduleloader.go setting module.Path and internal/configs/hcl2modulevars.go exposing it as a built-in variable.
  • This design ensures deterministic file operations by sandboxing paths to the actual code Terraform is executing.

Frequently Asked Questions

Does path.module change if I run Terraform from a different directory?

Yes. Since path.module for the root module always reflects the current working directory where you execute terraform apply, changing your shell's working directory changes the value of path.module in the root configuration. Child modules always point to their materialized locations under .terraform/modules/.

Why doesn't path.module point to the source URL for remote modules?

Terraform materializes all modules to the local filesystem under .terraform/modules/ to ensure deterministic execution and offline capability. The path.module variable references this local copy rather than the remote source URL to guarantee that file operations like file() or templatefile() work consistently regardless of network availability.

How do I get the original source path instead of the .terraform path?

You cannot retrieve the original source string (like github.com/org/repo//module) through path.module. If you need to reference the source location for documentation or debugging, you must track it manually in a variable or output. Terraform intentionally abstracts source locations to focus on the actual executing code.

Is path.module available during terraform plan and apply?

Yes. path.module is available during all phases of Terraform execution, including plan and apply. It is populated during the configuration loading phase before any resources are evaluated, making it safe to use in any expression, resource argument, or module output.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s https://instagit.com/install.md

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client