Article · part of a guide
How to Use terraform chdir
Learn how Terraform’s -chdir flag lets you run plans from any folder, streamline multi-dir projects, and speed up CI without changing directories.

Key takeaways
- The terraform -chdir=<PATH> global option, introduced in Terraform v0.14.0, makes Terraform switch to a specified directory before running a subcommand while the shell stays put.
- With -chdir, path.root points to the target directory while path.cwd still points to where you ran the command, which differs from cd DIR && terraform.
- Directory-based separation with -chdir gives each environment its own backend, provider versions, and state, offering stronger isolation than CLI workspaces.
- In Terraform Cloud or Enterprise, a workspace's Working Directory setting is the equivalent of -chdir for VCS-driven runs.
- As environments and teams grow, managing many separate -chdir contexts, variables, and policies adds operational overhead that platforms like Scalr centralize.
Fact checked by Ryan Fee on June 3, 2025.
Terraform defines and provisions infrastructure as code. As projects grow, you end up with multiple configurations: one for dev, staging, and prod, or one per microservice. Keeping them straight gets messy. And cd-ing into the right directory before every terraform apply is easy to get wrong, especially in an automated pipeline where a missed directory change runs the command in the wrong place. That's exactly what the -chdir flag is for.
What Exactly is 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.
Why Bother With -chdir?
The point of -chdir is to make juggling more than one Terraform setup less tedious.
- Cleaner Multi-Config Management: Got separate folders for dev, staging, and prod?
-chdirlets you target them without manually navigating. - Simpler Scripts: In your CI/CD pipelines or automation scripts, you don't need
cdcommands anymore. This makes your scripts cleaner and less likely to break if acdfails or isn't undone properly. - Less Context Switching: You can fire off commands for different parts of your infrastructure from one spot in your terminal.
- Fewer Errors: Less manual directory changing means fewer chances to run a command in the wrong place.
It's not quite the same as just doing cd DIR && terraform <command>. The difference is in 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. That's handy when a configuration needs to reference files outside its own directory but still inside the project.
Practical Ways to Use -chdir
Let's look at a few common scenarios.
1. Managing Multiple Environments
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, which gives you strong isolation. People usually reach for this over CLI workspaces when the backend configs or provider versions need to differ a lot between environments.
2. Component-Based Infrastructure
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.
3. CI/CD Pipelines
In a pipeline, -chdir keeps each step's target directory explicit.
# 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. The catch is that once you have a lot of these -chdir targets, orchestrating them, injecting variables, and keeping execution consistent across all of them in CI/CD starts to get complicated on its own.
-chdir vs. CLI Workspaces
Terraform CLI workspaces also let you manage multiple states from a single configuration. So which one fits your case?
- CLI Workspaces: Good for when you have minor variations of the same infrastructure and they can all share the same backend configuration. Think feature branches or temporary testing environments.
- Directory-Based Separation (with
-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. |
The -chdir approach gives you better isolation for distinct backends. The cost is that you now have many separate configurations to track, each with its own state and variables, and that tracking gets harder as the team grows.
-chdir and Backend/Provider/Module Management
- Backend Config: Terraform looks for backend configuration files (
backend.tf) inside the-chdirdirectory. The.terraformdirectory (with plugin caches and backend info) is also created and managed there. This is key for isolation. - Provider/Module Caching: By default, each
-chdirtarget directory gets its own cache of provider plugins and modules in its.terraformsubdirectory. This can mean downloading the same provider multiple times. To avoid this, you can set up a globalplugin_cache_dirin your Terraform CLI configuration file (terraform.rcorterraform.cfg). This is a good idea for performance, especially in CI. - Module
sourcePaths: Relative modulesourcepaths (e.g.,source = "../../shared_modules/network") are resolved relative to the configuration file within the-chdirtarget directory.
What About Terraform Cloud/Enterprise?
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. That's nice, because it means you can usually keep your multi-directory project structure when you move to a managed Terraform service.
Tips and Potential Snags
- Keep Structure Consistent: Use a clear, predictable directory layout (e.g.,
environments/<env_name>/,components/<component_name>/). - Automate It:
-chdiris really built for scripts and CI/CD. - Know Your Paths: Remember
path.rootis the-chdirtarget, andpath.cwdis where you ran the command. - Always
init: Runterraform -chdir=DIR initfor each target directory first. - Use
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.
Beyond -chdir: Scaling Challenges
The -chdir option beats navigating directories by hand. It brings clarity to local workflows and CI/CD scripts. But the work of managing those separate execution contexts doesn't go away as the number of environments, components, and teams grows. It just moves around.
Once you're leaning on -chdir plus custom scripting, a few things get hard at once. You have to keep execution consistent across dozens of configurations, handle variables and secrets safely, enforce policies like tagging or security group rules, and see all of your infrastructure in one place. This is usually where teams start looking for a platform instead. Scalr builds on these same concepts as a centralized control plane for Terraform operations. It offers 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. Those are hard to build and keep running yourself on top of raw -chdir workflows. See the pricing page for current plans.
Wrapping Up
terraform -chdir helps organize complex projects and makes automation cleaner. Once you know how it behaves with backends, workspaces, and modules, you can put it to work without surprises.
For a lot of teams, -chdir gives them all the control and organization they need. But as an IaC practice scales, managing a pile of separate configurations gets complicated, and that's often when people start looking at platforms like Scalr for more abstraction, governance, and collaboration across the whole setup.
About the Author
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.
Sources
- Terraform by HashiCorp. (n.d.). Retrieved from https://developer.hashicorp.com/terraform
- What is Infrastructure as Code? (n.d.). HashiCorp. Retrieved from https://www.hashicorp.com/en/resources/what-is-infrastructure-as-code
- Terraform CLI: Global Options. (n.d.). HashiCorp Developer. Retrieved from https://developer.hashicorp.com/terraform/cli/commands#global-options-for-all-commands (Primary reference for
-chdirsyntax and general global options) - Terraform CLI: -chdir Global Option. (n.d.). HashiCorp. (Note: Older documentation links might point to
terraform.io/cli/commands#chdir-option, butdeveloper.hashicorp.comis the current documentation portal. The-chdirdetails are typically integrated into the main global options page.) - GitHub Issue #26070:
**terraform: Add -chdir global option**. (2020, October 28). HashiCorp/terraform. Retrieved from https://github.com/hashicorp/terraform/issues/26070 - Terraform v0.14.0 Changelog. (2020, October 28). HashiCorp/terraform. Retrieved from https://github.com/hashicorp/terraform/blob/v0.14.0/CHANGELOG.md#0140-october-28-2020
- How to Manage Multiple Terraform Environments. (n.d.). Spacelift.
- Managing Multiple Environments in Terraform: Approaches and Best Practices. (n.d.). env0.
- When to use Multiple Workspaces. (n.d.). HashiCorp Developer. Retrieved from https://developer.hashicorp.com/terraform/language/state/workspaces#when-to-use-multiple-workspaces
- Terraform Best Practices for Scalable and Maintainable Infrastructure. (n.d.). Kinsta.
- Terraform: Managing Multiple Similar Environments. (2023, May 15). Medium. Retrieved from https://medium.com/@devopsbuddy/terraform-managing-multiple-similar-environments-f2c6a42793d8
- Provision an EC2 Instance (AWS). (n.d.). HashiCorp Developer. Retrieved from https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-create
- Command: init. (n.d.). HashiCorp Developer. Retrieved from https://developer.hashicorp.com/terraform/cli/commands/init
- Backend Configuration. (n.d.). HashiCorp Developer. Retrieved from https://developer.hashicorp.com/terraform/language/backend
- State: Local Backend. (n.d.). HashiCorp Developer. Retrieved from https://developer.hashicorp.com/terraform/language/backend/local
- Terraform -chdir and backend configuration. (2022, November). Reddit.
- GitHub Issue #28932:
**terraform init -chdir**fails with implicit filesystem mirror in CWD. (2021, May 20). HashiCorp/terraform. Retrieved from https://github.com/hashicorp/terraform/issues/28932 - Workspaces. (n.d.). HashiCorp Developer. Retrieved from https://developer.hashicorp.com/terraform/language/state/workspaces
- Terraform Workspaces: A Deep Dive. (2020, December 2). Medium. Retrieved from https://medium.com/globant/terraform-workspaces-a-deep-dive-117876969009
- Terraform Workspaces vs. Directories. (n.d.). Anton Babenko.
- CLI Configuration File: plugin_cache_dir. (n.d.). HashiCorp Developer. Retrieved from https://developer.hashicorp.com/terraform/cli/config/config-file#provider-plugin-cache
- GitHub Issue #22512: Feature request: Global module cache. (2019, August 1). HashiCorp/terraform. Retrieved from https://github.com/hashicorp/terraform/issues/22512
- Expressions: Path Variables. (n.d.). HashiCorp Developer.
- Workspaces Settings: Working Directory. (n.d.). Terraform Cloud Docs. HashiCorp Developer. Retrieved from https://developer.hashicorp.com/terraform/cloud-docs/workspaces/settings#working-directory
- Infrastructure as Code with OpenTofu and GitLab. (n.d.). GitLab Docs. Retrieved from https://docs.gitlab.com/user/infrastructure/iac/
- GitHub Issue #769: Add -chdir global option. (2021, January 28). terraform-linters/tflint. Retrieved from https://github.com/terraform-linters/tflint/pull/769
About the author

CEO at Scalr
Sebastian Stadil is the CEO of Scalr with 15+ years of DevOps experience. He started with AWS in 2004 and advised early Microsoft Azure and Google Cloud.
Part of this guide
9 sheets
The Developer's Guide to HCL
- Terraform moved blocks: refactoring without pain
- Terraform Outputs: How to with Examples
- Understanding the Terraform ignore_changes Lifecycle Block
- A Concise Guide to terraform_data Resource
- Advanced Terraform Workflows with terraform_data
- Terraform Resource Dependencies Explained
- The Three Stages of Terraform's Lifecycle Meta Argument