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.
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.
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 apply
This command would run terraform apply
using the configuration files located in the environments/production
subdirectory.
Why Bother With -chdir
?
The main idea is to make life easier when you're dealing with more than one Terraform setup.
- Cleaner Multi-Config Management: Got separate folders for dev, staging, and prod?
-chdir
lets you target them without manually navigating. - Simpler Scripts: In your CI/CD pipelines or automation scripts, you don't need
cd
commands anymore. This makes your scripts cleaner and less likely to break if acd
fails 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>
. 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.
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 apply
Each 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.
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 plan
This modularity is great for larger teams or when you want to limit the blast radius of changes.
3. CI/CD Pipelines
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 plan
No 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 Workspaces
Terraform CLI workspaces also let you manage multiple states from a single configuration. So, when do you use which?
- 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 |
Separate state files per workspace (e.g., |
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 |
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 Management
- Backend Config: Terraform looks for backend configuration files (
backend.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. - Provider/Module Caching: By default, each
-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 globalplugin_cache_dir
in your Terraform CLI configuration file (terraform.rc
orterraform.cfg
). This is a good idea for performance, especially in CI. - Module
source
Paths: Relative modulesource
paths (e.g.,source = "../../shared_modules/network"
) are resolved relative to the configuration file within the-chdir
target 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. This is great because it means you can often keep your multi-directory project structure when moving 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:
-chdir
is really built for scripts and CI/CD. - Know Your Paths: Remember
path.root
is the-chdir
target, andpath.cwd
is where you ran the command. - Always
init
: Runterraform -chdir=DIR init
for 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 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.
Wrapping Up
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.
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://www.terraform.io/
- What is Infrastructure as Code? (n.d.). HashiCorp. Retrieved from https://www.hashicorp.com/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
-chdir
syntax 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.com
is the current documentation portal. The-chdir
details 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/pull/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 environments with Terraform. (n.d.). Gruntwork. Retrieved from https://gruntwork.io/guides/devops-best-practices/how-to-manage-multiple-environments-with-terraform/
- How to Manage Multiple Terraform Environments. (n.d.). Spacelift. Retrieved from https://spacelift.io/blog/terraform-multiple-environments
- Managing Multiple Environments in Terraform: Approaches and Best Practices. (n.d.). env0. Retrieved from https://www.env0.com/blog/terraform-multiple-environments
- 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. Retrieved from https://kinsta.com/blog/terraform-best-practices/
- 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-build
- 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/settings/backends/configuration
- Where does terraform init store plugins? (2021, March 11). Stack Overflow. Retrieved from https://stackoverflow.com/questions/66587100/where-does-terraform-init-store-plugins
- State: Local Backend. (n.d.). HashiCorp Developer. Retrieved from https://developer.hashicorp.com/terraform/language/settings/backends/local
- Mastering Terraform: A Comprehensive Guide to Workspaces. (n.d.). Cloud Posse. Retrieved from https://cloudposse.com/blog/mastering-terraform-a-comprehensive-guide-to-workspaces/
- Terraform -chdir and backend configuration. (2022, November). Reddit. Retrieved from https://www.reddit.com/r/Terraform/comments/yzn3o3/terraform_chdir_and_backend_configuration/
- 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. Retrieved from https://www.antonbabenko.com/terraform-workspaces-vs-directories/
- 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. Retrieved from https://developer.hashicorp.com/terraform/language/expressions/path
- Workspaces Settings: Working Directory. (n.d.). Terraform Cloud Docs. HashiCorp Developer. Retrieved from https://developer.hashicorp.com/terraform/cloud-docs/workspaces/settings#working-directory
- Using Terraform with GitLab CI/CD: Multiple Environments. (n.d.). GitLab Docs. Retrieved from https://docs.gitlab.com/ee/ci/infrastructure/terraform_integration.html#multiple-terraform-environments
- GitHub Issue #769: Add -chdir global option. (2021, January 28). terraform-linters/tflint. Retrieved from https://github.com/terraform-linters/tflint/issues/769