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.

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.

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 a cd 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 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 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 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.
  • Module source Paths: Relative module source 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, and path.cwd is where you ran the command.
  • Always init: Run terraform -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