
This post is part of a series on The Developer's Guide to HCL.
Fact checked by Ryan Fee on June 3, 2025.
Terraform has become a go-to for defining and provisioning infrastructure using code. But as your projects grow, juggling multiple configurations—say, for dev, staging, and prod, or for different microservices—can get messy. Just cd-ing into the right directory before every terraform apply? It's a recipe for mistakes, especially in automated setups. That's where the -chdir flag comes in handy.
terraform -chdir?Introduced back in Terraform v0.14.0, -chdir=<PATH> is a global option that tells Terraform to switch to a specific directory before running the command you give it (like init, plan, or apply). Your shell's current directory stays put, but Terraform operates as if it's in the directory you pointed it to.
The basic syntax is:
terraform -chdir=<PATH_TO_CONFIG_DIRECTORY> <SUBCOMMAND>For example:
terraform -chdir=environments/production applyThis command would run terraform apply using the configuration files located in the environments/production subdirectory.
-chdir?The main idea is to make life easier when you're dealing with more than one Terraform setup.
-chdir lets you target them without manually navigating.cd commands anymore. This makes your scripts cleaner and less likely to break if a cd fails or isn't undone properly.It's not quite the same as just doing cd DIR && terraform <command>. A key difference is how Terraform sees paths. With -chdir, path.cwd (current working directory for Terraform) still points to where you ran the command from, while path.root points to the directory you specified with -chdir. This can be useful for configurations that need to reference files outside their own directory but within the broader project.
-chdirLet's look at a few common scenarios.
This is a big one. You probably have different setups for development, staging, and production. A common project structure might be:
my-project/
├── environments/
│ ├── dev/
│ │ └── main.tf
│ ├── staging/
│ │ └── main.tf
│ └── production/
│ └── main.tf
└── modules/
└── ...
From the my-project/ root, you can manage each environment:
# Initialize development
terraform -chdir=environments/dev init
# Plan changes for production
terraform -chdir=environments/production plan
# Apply changes to staging
terraform -chdir=environments/staging applyEach of these environment directories can have its own backend configuration, provider versions, and variable files, offering strong isolation. This is often preferred over CLI workspaces when backend configurations or even provider versions need to differ significantly between environments.
If your system is broken into smaller pieces (VPC, DNS, app services, databases), -chdir helps manage them independently.
my-infra/
├── vpc/
│ └── main.tf
├── dns/
│ └── main.tf
├── app-service-a/
│ └── main.tf
└── database-main/
└── main.tf
You can then target specific components:
terraform -chdir=my-infra/vpc apply
terraform -chdir=my-infra/app-service-a planThis modularity is great for larger teams or when you want to limit the blast radius of changes.
In automation, -chdir shines by making pipeline definitions more straightforward.
# Example CI/CD pipeline steps
jobs:
deploy-dev:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
- name: Init Dev VPC
run: terraform -chdir=environments/dev/vpc init
- name: Apply Dev VPC
run: terraform -chdir=environments/dev/vpc apply -auto-approve
deploy-prod-app:
runs-on: ubuntu-latest
needs: deploy-dev # Example dependency
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
- name: Init Prod App
run: terraform -chdir=environments/prod/app init
- name: Plan Prod App
run: terraform -chdir=environments/prod/app planNo more cd some/path && terraform apply && cd ../.. gymnastics. Each step is explicit about its target. However, as the number of these -chdir targets grows, managing the orchestration, variable injection, and ensuring consistent execution across all of them in a CI/CD system can introduce its own layer of complexity.
-chdir vs. CLI WorkspacesTerraform CLI workspaces also let you manage multiple states from a single configuration. So, when do you use which?
-chdir): Better when environments need different backend configurations, different provider versions, or have significantly different infrastructure. This provides stronger isolation.Here’s a quick comparison:
| Feature | Directory-Based with -chdir | CLI Workspaces |
|---|---|---|
| Backend Configuration | Can be entirely separate per directory (different types, accounts, credentials). | Shared by all workspaces within the same working directory configuration. |
| State File Location | Each directory has its own terraform.tfstate (or remote equivalent) and .terraform dir. |
Separate state files per workspace (e.g., terraform.tfstate.d/<workspace_name>/terraform.tfstate for local backend) within one config dir. |
| Provider Configuration | Can be separate per directory (different versions, aliases). | Shared by all workspaces. |
| Code Duplication | Higher risk if not using modules effectively; configurations are physically separate. | Lower; uses the same set of .tf files, with variations via terraform.workspace or input variables. |
| Isolation Level | Stronger; physical separation of configuration, state, and backend. | Weaker; all workspaces share the same backend configuration and often the same credentials. |
| Ideal Use Cases | Managing distinct environments (dev, prod) with different backends/credentials, complex components. | Managing minor variations of the same infrastructure (e.g., feature branches, parallel test environments) with a shared backend. |
While -chdir offers better isolation for distinct backends, keeping track of numerous, separate configurations, each potentially with its own state and variables, can become a significant organizational and operational task, especially as teams scale.
-chdir and Backend/Provider/Module Managementbackend.tf) inside the -chdir directory. The .terraform directory (with plugin caches and backend info) is also created and managed there. This is key for isolation.-chdir target directory gets its own cache of provider plugins and modules in its .terraform subdirectory. This can mean downloading the same provider multiple times. To avoid this, you can set up a global plugin_cache_dir in your Terraform CLI configuration file (terraform.rc or terraform.cfg). This is a good idea for performance, especially in CI.source Paths: Relative module source paths (e.g., source = "../../shared_modules/network") are resolved relative to the configuration file within the -chdir target directory.If you're using Terraform Cloud or Enterprise, the "Working Directory" setting in a workspace is basically the -chdir equivalent. TFC/TFE will "change to" that directory in your VCS repo before running Terraform commands. This is great because it means you can often keep your multi-directory project structure when moving to a managed Terraform service.
environments/<env_name>/, components/<component_name>/).-chdir is really built for scripts and CI/CD.path.root is the -chdir target, and path.cwd is where you ran the command.init: Run terraform -chdir=DIR init for each target directory first.plugin_cache_dir: It'll speed things up.A known issue can pop up with terraform init -chdir if you're using implicit filesystem mirrors for providers (like a terraform.d/plugins/ in your current directory). Terraform might get confused about where to find them. The workaround is often to move that mirror relative to the -chdir target, or better yet, rely on the official provider registry or explicit provider_installation blocks.
-chdir: Scaling ChallengesThe -chdir option is a solid improvement over manually navigating directories for managing multiple Terraform configurations. It brings clarity to local workflows and CI/CD scripts. However, as the number of environments, components, and teams grows, the operational overhead of managing these distinct -chdir execution contexts doesn't just disappear.
Ensuring consistency in execution, managing variables and secrets securely across dozens of configurations, enforcing organizational policies (like tagging or security group rules), and getting a unified view of all your infrastructure can become challenging when relying solely on -chdir and custom scripting. This is often where organizations start to feel the need for a more comprehensive platform. Solutions like Scalr build upon these foundational concepts by providing a centralized control plane for all your Terraform operations. They can offer features like hierarchical variable management, role-based access control (RBAC) scoped to environments or components, automated policy enforcement (via OPA, for example), and cost estimation before changes are applied—things that are hard to build and maintain yourself on top of raw -chdir workflows.
terraform -chdir is a valuable tool in your Terraform toolkit. It helps organize complex projects and makes automation cleaner. By understanding how it works with backends, workspaces, and modules, you can use it effectively.
For many, -chdir provides the right level of control and organization. But as your IaC practice matures and scales, the inherent complexities of managing numerous, disparate configurations might lead you to look for platforms that offer a higher level of abstraction, governance, and collaboration—like Scalr—to truly master your infrastructure lifecycle.
Sebastian Stadil, CEO and founder of Scalr, brings over 15 years of DevOps experience. His experience dates back to using AWS in 2004, even before the S3 public beta. He is also the program chair for OpenTofu at the Linux Foundation and previously advised Microsoft Azure and Google Cloud, serving a combined ten years on their respective Cloud Advisory Boards.
-chdir syntax and general global options)terraform.io/cli/commands#chdir-option, but developer.hashicorp.com is the current documentation portal. The -chdir details are typically integrated into the main global options page.)**terraform: Add -chdir global option**. (2020, October 28). HashiCorp/terraform. Retrieved from https://github.com/hashicorp/terraform/pull/26070**terraform init -chdir** fails with implicit filesystem mirror in CWD. (2021, May 20). HashiCorp/terraform. Retrieved from https://github.com/hashicorp/terraform/issues/28932