Skip to content
WSLDeep Dive Published Updated 7 min readViews unavailable

Terraform in WSL: Working Directories, Providers, and Safe Plans

Run Terraform from WSL with Linux-side providers and state, inspect init and lockfiles, review plans carefully, and avoid cross-platform cache confusion.

Terraform’s CLI is a useful WSL tool when a team wants Linux shell behavior, CI parity, and a single environment for providers and modules. Its working directory is more than a folder of .tf files: it holds initialization metadata and plugin/module downloads, and may contain local state depending on the configured backend. A successful terraform plan is a preview for one specific configuration, workspace, backend, variable set, and provider version. It is not a change approval by itself.

Keep the configuration checkout, .terraform working metadata, plugin cache, and any local state under the Linux filesystem. Microsoft recommends Linux storage for Linux workloads. Windows-native Terraform and WSL Terraform should not share a mutable working directory or cache unless that setup is explicitly supported and tested; provider executables and path conventions may differ. Use version control to share configuration, not copied state or generated plugin directories.

Pin and verify the CLI environment

Install Terraform using HashiCorp’s current platform instructions, then record terraform version and the operating system/architecture. Project teams may also pin Terraform with a version manager or CI toolchain file. Do not upgrade the global CLI or provider versions merely because the command is available in a package manager; review provider compatibility and lockfile changes for the repository.

Terraform initialization downloads providers and modules and configures the selected backend. The official documentation says the dependency lock file records provider selections and should be committed when changes are intentional. Review .terraform.lock.hcl diffs rather than deleting it to resolve a provider mismatch. Keep local plugin caches out of source control and do not assume two operating systems can reuse the same cached executable artifact.

Separate local experimentation from remote state

Terraform uses the current working directory as the root module context. The .terraform directory stores initialization metadata; the default local backend can create terraform.tfstate alongside the configuration. A remote backend has different locking, identity, and recovery behavior. Know which backend is active before running commands that read state or contact a service.

For a disposable syntax exercise, use a scratch copy of a small configuration and explicitly disable backend initialization where that is appropriate for the test. terraform validate requires the directory to be initialized and providers to be available, so a purely local validation can still download plugins. Do not point a test at a production backend simply to make the first command succeed. Never commit a real state file, plan file, credentials, or backend secrets without following the repository’s data-handling policy.

Run the formatter and inspect its changes before initialization:

terraform fmt -check -recursive
terraform init -backend=false
terraform validate

The exact flags and behavior are documented by the Terraform CLI. This example is for a disposable configuration that does not need its configured remote backend. If the project requires a backend, use its approved workspace and confirm the selected account and state key first. init is designed to be repeatable, but it may download modules and provider plugins and update initialization metadata.

Review plans as structured change proposals

terraform plan compares configuration with prior state and observed remote objects to produce proposed actions. By default it can refresh objects in the selected provider account. That means even plan is not merely a static parser: it may contact APIs, consume permissions, and reveal information in output. Use a dedicated development account and a test workspace for local experiments.

Read the full plan, not just the summary count. Check resource addresses, replacements, deletions, sensitive values, provider aliases, data sources, and module versions. A plan created with one variable set should not be applied under another. Saved plans are artifacts tied to configuration and state; protect them and review them before use. Do not run apply from this article’s lab unless the configuration targets a disposable resource and the resulting plan is explicitly intended.

WSL path differences can affect provisioners and local-file data sources. A path like /home/user/project is meaningful to the Linux Terraform process, while a Windows drive path has a different syntax and permission boundary. Avoid making configuration depend on a developer’s home directory. Use module inputs and project-relative paths where possible, and test any local-exec provisioner inside the same WSL shell used by CI.

Keep provider, module, and credential boundaries visible

Providers are executable plugins and can access the APIs permitted by their credentials. Download them from trusted registries or an approved mirror, constrain versions in configuration, and commit the lockfile. A WSL shell may inherit Windows proxy or credential variables through interop; inspect the environment that Terraform actually receives and avoid printing secret values into logs.

Use separate credentials and workspaces for local validation. Do not rely on a developer’s cloud login silently supplying privileges absent from CI. If a provider requires application credentials, use its documented environment variables or credential chain with the least privilege needed for the target. When a backend uses remote state locking, verify that concurrent runs from WSL and CI use the same backend and locking mechanism; separate local copies of state can diverge.

Remote state and local state have different coordination guarantees. A local state file does not coordinate with another developer’s checkout, and two processes with separate local copies can each produce internally consistent but conflicting plans. A remote backend with locking can protect supported operations, but only when all participants use the same backend and locking is enabled. Do not copy local state between WSL and Windows worktrees to resolve a workspace mismatch; identify the active backend and workspace instead.

When automation saves a plan, protect that plan file like state because it can contain sensitive values and binds a proposed change to a particular context. HashiCorp documents the workflow of creating a saved plan and applying that saved plan later. For a local review, inspect the plan in the same workspace and identity that created it, verify its age and target, and do not apply an artifact that was generated before intervening configuration or state changes.

Backend configuration may contain organization names, workspace identifiers, or authentication references. Keep secrets out of .tf source and use the provider/backend’s supported credential chain. If the WSL shell inherits credentials from Windows, identify which identity Terraform will actually use. A plan showing no changes under the wrong account is not evidence that the intended environment is converged.

Workspace names are not a substitute for a state-isolation design. Before selecting a workspace, verify which backend and state object the current directory has initialized, and confirm the account and region from the provider configuration. A familiar workspace name can still point at an unintended remote state if backend configuration or environment variables changed. For an isolated lab, use a disposable local configuration or a dedicated test backend with a clearly separated key. Capture the workspace and state identity alongside the plan so a reviewer can relate the proposed diff to the object that Terraform actually read.

Diagnose common WSL issues

If provider installation fails, inspect proxy/DNS configuration, registry availability, architecture, and lockfile checksums. If terraform validate reports a provider schema issue, compare the selected provider version with the lockfile and reinitialize only the intended working directory. If a plan proposes unexpected replacement, inspect immutable resource attributes, provider version, workspace, variables, and refreshed remote state before changing the configuration.

If a script cannot find a binary, inspect PATH from the WSL process rather than Windows. If operations are slow, distinguish provider downloads, module retrieval, backend latency, state refresh, and filesystem placement. Do not clear every .terraform directory as a general repair; capture the failure and identify whether the stale element is a provider cache, module cache, backend initialization record, or state file.

Acceptance criteria

Accept the WSL Terraform setup when the CLI and provider versions are recorded, the checkout and caches are Linux-side, the active backend/workspace/account are known, initialization and validation succeed in a disposable context, and plans are reviewed against the intended variable and state set. Keep lockfile changes intentional and state protected.

Terraform in WSL is a practical infrastructure-development CLI. It does not make plans safe by default, and local execution is not a substitute for remote-state coordination, peer review, or a controlled apply process.

Related:

Sources:

Comments