Manage Multiple Terraform/OpenTofu Versions
Learn how to install and manage multiple versions of Terraform and OpenTofu using the Atmos toolchain manager.
Overview
Atmos includes a built-in toolchain manager that can install and manage multiple versions of Terraform, OpenTofu, and other infrastructure tools. This is useful when:
- Different projects require different Terraform versions
- You need to test compatibility with newer versions
- Your team needs consistent tool versions across machines
Installing Tool Versions
Install a Specific Version
# Install a specific Terraform version
atmos toolchain install terraform@1.9.0
# Install a specific OpenTofu version
atmos toolchain install opentofu@1.8.0
Install the Latest Version
# Install the latest Terraform
atmos toolchain install terraform@latest
# Install the latest OpenTofu
atmos toolchain install opentofu@latest
Using .tool-versions
The .tool-versions file (compatible with asdf) allows you to pin tool versions per project:
terraform 1.9.0
opentofu 1.8.0
When you run atmos terraform plan, Atmos uses .tool-versions as the project's default tool environment. With the default toolchain.install: auto policy, if the file pins the component's executable (terraform, or tofu when the component sets command: tofu), Atmos installs that version when it is missing. Other tools in the file are added to PATH only if they are already installed, for example with atmos toolchain install. If a tool lists multiple versions, the first is its default. Terraform output lookups, including !terraform.output and atmos.Component(), use these defaults too.
Every Atmos command inherits already-installed versions selected by the file on PATH. Cached tools absent from the file, and other cached versions, are not added. Explicit dependencies.tools override the baseline; installation policy controls downloads separately. Under auto:
- Helmfile components also install
helmwhen the file pins it. - Custom commands and hooks use only the tools that are already installed. Atmos installs just their own
dependencies.tools. - Workflows install every tool listed in
.tool-versionsthat is missing before running the first step, because a workflow can call any project tool.
Set toolchain.install to change how eagerly Atmos installs tools:
toolchain:
install: auto # never | declared | auto | always
neverinstalls nothing. Tools are used only when already installed, and a missingdependencies.toolsentry is an error.declaredinstalls onlydependencies.tools(and, for workflows, every.tool-versionstool). Other runs inherit installed project selections without installing missing defaults. Projects pinned to an edition before 2026-10-09 get this value automatically.autois the default described above.alwaysinstalls every tool in.tool-versionsfor every run.
If the file does not pin the component's executable, Atmos installs nothing for it and uses the system PATH. Entries with the version system, ref:..., or path:..., a bare operator such as ~> (write ~>1.9.0 without a space), or a tool name Atmos cannot resolve are skipped without failing the run, as are lines that list a tool without a version (with a warning). Two entries for the same tool with different versions, such as tofu 1.12.6 and opentofu/opentofu 1.11.0, are an error.
Explicit dependencies.tools entries always override .tool-versions, even when they select a different version or use a version constraint. For example:
hashicorp/terraform 1.9.0
components:
terraform:
legacy-vpc:
dependencies:
tools:
terraform: "1.8.5"
Here, legacy-vpc uses Terraform 1.8.5; components without an override use 1.9.0. Atmos treats a short name or configured alias and its qualified name as the same tool when it compares the manifest with explicit dependencies, so terraform overrides hashicorp/terraform. Running the component does not change the project pin in .tool-versions.
Precedence is .tool-versions → stack-wide dependencies.tools → component-type dependencies → component-instance dependencies. Existing constraint checks between explicit stack scopes still apply. If neither the manifest nor stack configuration declares a tool, Atmos falls back to the system PATH.
Setting Versions
# Set Terraform version for current project
atmos toolchain set terraform@1.9.0
# This creates or updates .tool-versions
Listing Installed Versions
# List all installed tools
atmos toolchain list
# Search for available Terraform versions
atmos toolchain registry search terraform
Component-Level Versions in Stacks
Different Terraform components can use different versions. This is useful when:
- Legacy components require older Terraform versions
- New components need features from newer versions
- Gradual upgrades without breaking existing infrastructure
Global Tool Dependencies
Define default versions at the root level of your stack:
# Global tool dependencies - applies to all components
dependencies:
tools:
terraform: "1.9.8"
kubectl: "1.28.0"
Component-Type Dependencies
Override for all Terraform components:
terraform:
dependencies:
tools:
terraform: "1.9.8"
tflint: "0.44.1"
Per-Component Override
Specify versions for individual components:
components:
terraform:
vpc:
dependencies:
tools:
terraform: "1.9.8" # Use current version
aws-cli: "2.13.0"
legacy-app:
dependencies:
tools:
terraform: "1.5.0" # Legacy component needs older version
aws-cli: "2.10.0"
How It Works
When you run a component, Atmos automatically:
- Resolves the tool version from the most specific level
- Installs the tool if not already cached
- Executes the command with that version
# Uses terraform 1.9.8 (from vpc component config)
atmos terraform plan vpc -s prod/us-east-1
# Uses terraform 1.5.0 (from legacy-app component config)
atmos terraform plan legacy-app -s prod/us-east-1
For complete documentation on component dependencies, see Configure Dependencies.
Best Practices
- Pin exact versions in CI/CD: Use exact versions (e.g.,
1.9.0) in pipelines for reproducibility - Use constraints in development: Allow minor version flexibility (e.g.,
>=1.9.0, <1.10.0) for local development - Commit .tool-versions: Include
.tool-versionsin version control so the team uses consistent versions - Test upgrades in isolation: Install new versions and test before updating
.tool-versions
See Also
- Configure Dependencies - Component-level tool version configuration
- Toolchain Commands
- Toolchain Configuration