About us

We are tofuutils, a dedicated team of developers passionate about creating modern, efficient tools for streamlining Infrastructure-as-Code (IaC) management. 

Our flagship project, tenv, is an open-source solution designed to simplify version management for key IaC tools like Terraform, OpenTofu, Terragrunt, and Atmos. 

We strive to provide powerful and flexible tools to enhance the development workflow, which is why we’ve made tenv fast and adaptable, for seamless integration into your day-to-day work.

Our tofuutils team, who’s been working on tenv and tofuenv development (Alexander Sharov, Denis Vaumoron, Nikolay Mishin, and Anastasiia Kozlova) believe that tenv will help developers and DevOps to stop struggling with and spending time on IaC tools management, and we’re excited to help!

Introduction

Infrastructure-as-Code (IaC) is a widely used approach to managing and provisioning infrastructure. It’s a constantly changing field: the list of IaC tools is always growing, not to mention that each tool is being actively developed, releasing new features, enhancements, and bug fixes at least once a week.

However, keeping track of all these changes can be complicated, especially when it comes to managing different versions of IaC tools. With multiple projects, it can quickly become a nightmare. Each project might require a specific version of the IaC tool or its dependencies, leading to potential conflicts and compatibility issues.

Moreover, with the release of OpenTofu, most of us may need to use both it and Terraform, and perhaps some other Terraform wrappers such as Terragrunt; having to track several tools becomes a constant headache.

The solution

A dedicated version manager able to manage those tools and their versions, handle their installation, and control versions in each project even if you have a thousand of them 🥵 would be really convenient, right? The answer is right here – tenv.

tenv is a version manager for Terraform, OpenTofu, Terragrunt, and Atmos, written in Go. This versatile version manager simplifies the complexity of version control, helping you avoid spending time on IaC tools’ version management and ensuring developers and DevOps can focus on what matters most: crafting innovative products and driving business value.

tenv main features

tenv has the following key features:

  • Versatile version management: currently supports managing four main IaC tools: Terraform, OpenTofu, Terragrunt, and Atmos.
  • Signature verification: supports cosign and PGP.
  • Intuitive installation: simple installation process with Homebrew and manual options.
  • Semver 2.0.0 compatibility: can extract required version constraints from OpenTofu/Terraform/Terragrunt files.
  • Backwards compatibility: supports versions files used by tfenv and tofuenv tools (.terraform-version and .opentofu-version, accordingly).  

What makes tenv unique

tenv is a version management tool specifically tailored for managing Terraform, OpenTofu, Terragrunt and Atmos. 

Unlike tools such as asdf, tfenv, and tofuenv, tenv is distributed as binaries, making it OS-independent. This distribution method enhances tool performance, providing the Go-based tenv with greater efficiency and flexibility. At this moment, tenv is available for all major operating systems such as MacOS, Windows, Linux, BSD, and Solaris.

While tenv shares similar goals with tfswitch, a solid tool for Terraform version management, it stands out by supporting a broader range of tools, including OpenTofu, Terragrunt, and Atmos. 

tenv is designed with unique features for each of these tools, enabling seamless project management and smooth migration between them. Coupled with active and thorough development, tenv offers a robust solution for managing multiple IaC tool versions efficiently.

Moveover, if you’re already using asdf and want to try tenv without the overhead of an additional tool installation, tenv offers an official plugin.

Getting started

Install tenv

tenv can be installed on all modern operating systems: MacOS, Ubuntu, Arch Linux, BSD and Windows. To simplify the installation process, all popular package managers are supported: brew, chocolatey, nix, yay, apk, snap and several others. Let’s look at some of them below:

You can use brew to install tenv in MacOS environment:

$ brew install tenv

You can use choco to install tenv to Windows environment:

$ choco install tenv

More detailed installation instructions can be found in the GitHub repo.

A manual installation of the packaged binaries is also available. Simply download a binary suitable for your OS (.deb, .rpm, .apk, pkg.tar.zst , .zip or .tar.gz format) by visiting the release page. After downloading, unzip the folder and seamlessly integrate it into your system's PATH.

Finally, tenv can be run in a CI pipeline using a prebuilt Docker image:

$ docker run -it --rm tofuutils/tenv:latest help

After the installation, your tenv version can be checked via [.code]version[.code] command:

$ tenv version
tenv version v1.6.2

How it works

tenv is designed to seamlessly support OpenTofu, Terraform, Terragrunt, and Atmos. All tools can be managed via [.code]tenv <tool> <command>[.code], where tool (alias) is:

Alias Env vars prefix Tool
tf TFENV Terraform
tofu TOFUENV OpenTofu
tg TG Terragrunt
atmos ATMOS Atmos

tenv is distributed as a set of binaries. The tenv binary acts as a proxy, calling the specific tool’s binary (e.g., terraform/tofu/terragrunt/atmos), based on the subcommand passed down from the table above.

Using tenv

The list of commands for each tool can be checked with [.code]help[.code] command. Let’s check for Terraform (tf):

$ tenv tf help
Subcommand to manage several versions of Terraform (https://www.terraform.io).
Usage:
  tenv tf [command]
Aliases:
  tf, terraform
Available Commands:
  constraint  Set a default constraint expression for Terraform.
  detect      Display Terraform current version.
  install     Install a specific version of Terraform.
  list        List installed Terraform versions.
  list-remote List installable Terraform versions.
  reset       Reset used version of Terraform.
  uninstall   Uninstall a specific version of Terraform.
  use         Switch the default Terraform version to use.
Flags:
  -h, --help   help for tf
Global Flags:
  -q, --quiet              no unnecessary output (and no log)
  -r, --root-path string   local path to install versions of OpenTofu, Terraform and Terragrunt
  -v, --verbose            verbose output (and set log level to Trace)
Use "tenv tf [command] --help" for more information about a command.

Alternatively, an alias for tf - terraform - can be used:

$ tenv terraform help

In the same way, we can get info about the command available for OpenTofu (tofu, opentofu) and Terragrunt (tg, terragrunt) management.

Now, let’s explore the functionality tenv provides.

Install IaC tool

To install OpenTofu, Terraform, Terragrunt or Atmos, we need to run the install command with a required tool name/alias. Let’s install OpenTofu as example:

$ tenv tofu install
No version files found for OpenTofu, fallback to latest strategy
Fetching all releases information from https://api.github.com/repos/opentofu/opentofu/releases
Found compatible version remotely : 1.6.2
Installing OpenTofu 1.6.2
Fetching release information from https://api.github.com/repos/opentofu/opentofu/releases/tags/v1.6.2
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.2/tofu_1.6.2_darwin_amd64.zip
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.2/tofu_1.6.2_SHA256SUMS
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.2/tofu_1.6.2_SHA256SUMS.sig
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.2/tofu_1.6.2_SHA256SUMS.pem
cosign executable not found, fallback to pgp check
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.2/tofu_1.6.2_SHA256SUMS.gpgsig
Downloading https://get.opentofu.org/opentofu.asc
Installation of OpenTofu 1.6.2 successful

By default, the latest version is downloaded. However, a specific version of the IaC tool can also be installed when needed. Let’s try to install version 1.5.7 of Terraform:

$ tenv tf install 1.5.7
Installing Terraform 1.5.7
Fetching release information from https://releases.hashicorp.com/terraform/1.5.7/index.json
Downloading https://releases.hashicorp.com/terraform/1.5.7/terraform_1.5.7_darwin_amd64.zip
Downloading https://releases.hashicorp.com/terraform/1.5.7/terraform_1.5.7_SHA256SUMS
Downloading https://releases.hashicorp.com/terraform/1.5.7/terraform_1.5.7_SHA256SUMS.sig
Downloading https://www.hashicorp.com/.well-known/pgp-key.txt
Installation of Terraform 1.5.7 successful

The install command also supports version constraints such as:

  • latest - the latest available stable version
  • latest-pre - the latest available version, including unstable ones
  • latest-allowed or min-required - tenv will scan our IaC tools’ files to detect which version is maximally allowed or minimally required. 

Let’s use latest-pre to install the latest available version of OpenTofu:

$ tenv tofu install latest-pre  
Fetching all releases information from https://api.github.com/repos/opentofu/opentofu/releases
Found compatible version remotely : 1.7.0-alpha1
Installing OpenTofu 1.7.0-alpha1
Fetching release information from https://api.github.com/repos/opentofu/opentofu/releases/tags/v1.7.0-alpha1
Downloading https://github.com/opentofu/opentofu/releases/download/v1.7.0-alpha1/tofu_1.7.0-alpha1_darwin_amd64.zip
Downloading https://github.com/opentofu/opentofu/releases/download/v1.7.0-alpha1/tofu_1.7.0-alpha1_SHA256SUMS
Downloading https://github.com/opentofu/opentofu/releases/download/v1.7.0-alpha1/tofu_1.7.0-alpha1_SHA256SUMS.sig
Downloading https://github.com/opentofu/opentofu/releases/download/v1.7.0-alpha1/tofu_1.7.0-alpha1_SHA256SUMS.pem
skip signature check : cosign executable not found and pgp check not available for unstable version
Installation of OpenTofu 1.7.0-alpha1 successful

We can also use the [.code]-q (--quiet)[.code] flag to have no logs/only important ones printed to the output.

$ tenv tofu install 1.6.0 -q

However, it would be good to know which versions of the tools are available for installation before choosing one. Luckily, tenv can help with this too!

List IaC tool versions

First, tenv has a command list-remote, which provides you with a list of all IaC tool versions available for installation. Let’s try to get one for Terragrunt (some versions in the middle have been omitted):

$ tenv tg list-remote
Fetching all releases information from https://api.github.com/repos/gruntwork-io/terragrunt/releases
0.0.4
0.0.5
0.0.6
0.0.7
0.0.8
0.0.9
0.0.10
0.0.11
0.1.0
0.55.21
0.56.0
0.56.1
0.56.2

Similarly, tenv can help to check the list of IaC tool versions already installed locally (shown here for OpenTofu):

$ tenv tofu list            
  1.6.0
  1.6.2
  1.7.0-alpha1

Automatic version management for IaC tool

tenv has the [.code]detect[.code] command that returns the version of the tool binary used for the current project. The tool version resolution is not straightforward, since the version can be set in several places. 

Let’s explore this example of version resolution for Terraform. The extended list of  IaC tools be found in tenv repo docs.

tenv checks Terraform version in the following order:

  • [.code]TFENV_TERRAFORM_VERSION[.code] environment variable
  • .terraform-version file
  • .tfswitchrc file
  • [.code]terraform_version_constraint[.code] from terragrunt.hcl file
  • [.code]terraform_version_constraint[.code] from terragrunt.hcl.json file
  • [.code]TFENV_TERRAFORM_DEFAULT_VERSION[.code] environment variable
  • ${TENV_ROOT}/Terraform/version file (can be written with tenv tf use)
  • latest-allowed

If no versions are found in the list above, the latest available stable version will be used by tenv.

While environment variables from the list above can be set manually, let’s focus on the version files. 

There is a list of version files supported by tenv for different tools. A version file should be placed in the working directory, one of its parent directories, or user home directory (in which case tenv detects it and uses that version). 

Thus, using proper version files in different projects allows you to switch versions automatically without running any additional commands.

tenv supports the following version files:

  • .opentofu-version - Opentofu version file. tenv will detect and use the version written in it
  • .terraform-version or .tfswitchrc - Terraform version file. tenv will detect and use the version written in it
  • .terragrunt-version or .tgswitchrc - Terragrunt version file. tenv will detect and use the version written in it
  • terragrunt.hcl or terragrunt.hcl.json - tenv will read constraint from the [.code]terraform_version_constraint[.code] or [.code]terragrunt_version_constraint[.code] field in it (depending on the proxy or subcommand used)
  • .atmos-version - Atmos version file. tenv will detect and use the version written in it
  • .tf or .tf.json IaC files - tenv will use version constraints from there when using the latest-allowed or min-required strategies

Let’s try it out with OpenTofu. First, we don’t set any specific versions.

$ tenv tofu detect
No version files found for OpenTofu, fallback to latest-allowed strategy
Scan project to find .tf files
No OpenTofu version requirement found in project files, fallback to latest strategy
Found compatible version installed locally : 1.6.2
OpenTofu 1.6.2 will be run from this directory.

No version set was found, so the latest stable one is used by default. Now let’s set the [.code]TOFUENV_TOFU_DEFAULT_VERSION[.code] variable to 1.6.0.

$ tenv tofu detect                         
Resolved version from TOFUENV_TOFU_DEFAULT_VERSION : 1.6.0
OpenTofu 1.6.0 already installed
OpenTofu 1.6.0 will be run from this directory.

In this case, tenv found a specific version set, so now our project will use this one instead of the latest 1.6.1. 

However, in some cases we may have projects already using a newer version, but we want to keep the default one to be 1.6.0. We can create an .opentofu-version file in our project’s directory and specify the version there.

$ echo 1.6.1 > .opentofu-version
$ tenv tofu detect              
Resolved version from .opentofu-version : 1.6.1
Installing OpenTofu 1.6.1
Fetching release information from https://api.github.com/repos/opentofu/opentofu/releases/tags/v1.6.1
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.1/tofu_1.6.1_darwin_amd64.zip
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.1/tofu_1.6.1_SHA256SUMS
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.1/tofu_1.6.1_SHA256SUMS.sig
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.1/tofu_1.6.1_SHA256SUMS.pem
cosign executable not found, fallback to pgp check
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.1/tofu_1.6.1_SHA256SUMS.gpgsig
Downloading https://get.opentofu.org/opentofu.asc
Installation of OpenTofu 1.6.1 successful
OpenTofu 1.6.1 will be run from this directory.
$ cd ..
$ tenv tofu detect
Resolved version from TOFUENV_TOFU_DEFAULT_VERSION : 1.6.0
OpenTofu 1.6.0 already installed
OpenTofu 1.6.0 will be run from this directory.

After setting the 1.6.1 version of OpenTofu in the version file, tenv detected this version instead of 1.6.0, set in the [.code]TOFUENV_TOFU_DEFAULT_VERSION[.code] variable.

If the Opentofu binary for this version is not present, tenv will install it. 

However, after changing the working directory to one level above, tenv detected the 1.6.0 OpenTofu version again, since no .opentofu-version file was presented in that path or in any parent directory, nor in a user’s home directory. The version from the [.code]environment[.code] variable was used instead.

Use specific version

tenv also has a [.code]tenv <tool> use[.code] command which allows you to manually choose the version of the tool you currently want to use. This version is written to the [.code]TENV_ROOT/<TOOL>/version[.code] file. Let’s try with Terraform:

$ tenv tf use 1.5.6
Installing Terraform 1.5.6
Fetching release information from https://releases.hashicorp.com/terraform/1.5.6/index.json
Downloading https://releases.hashicorp.com/terraform/1.5.6/terraform_1.5.6_darwin_amd64.zip
Downloading https://releases.hashicorp.com/terraform/1.5.6/terraform_1.5.6_SHA256SUMS
Downloading https://releases.hashicorp.com/terraform/1.5.6/terraform_1.5.6_SHA256SUMS.sig
Downloading https://www.hashicorp.com/.well-known/pgp-key.txt
Installation of Terraform 1.5.6 successful
Written 1.5.6 in /Users/tofuutils/.tenv/Terraform/version

Version 1.5.6 of Terraform was set to use. Same as for the [.code]detect[.code] command – if no binary is found for the version specified, it will be installed by tenv automatically. 

The [.code]TENV_ROOT/<TOOL>/version[.code] can be removed via the [.code]tenv <tool> reset[.code] command.

$ tenv tofu use 1.6.1             
Written 1.6.1 in /Users/tofuutils/.tenv/OpenTofu/version
$ ls ~/.tenv/OpenTofu/version 
/Users/tofuutils/.tenv/OpenTofu/version
$ cat ~/.tenv/OpenTofu/version 
1.6.1
$ tenv tofu reset
Removed /Users/tofuutils/.tenv/OpenTofu/version
$ cat ~/.tenv/OpenTofu/version
cat: /Users/tofuutils/.tenv/OpenTofu/version: No such file or directory

If we want to change the default behavior and disable the automatic installation, we can set the variable [.code]TENV_AUTO_INSTALL[.code] to [.code]false[.code].

$ export TENV_AUTO_INSTALL=false
$ tenv tf use 1.5.4             
Written 1.5.4 in /Users/tofuutils/.tenv/Terraform/version
$ terraform init
Failure during terraform call : fork/exec /Users/tofuutils/.tenv/Terraform/1.5.4/terraform: no such file or directory

As you can see, Terraform version in use was changed to 1.5.4, but since no installation occurred by default, and this version was not installed before, we got an error when trying to run terraform.

Auto installation property can also be controlled for a specific tool only, i.e., [.code]<tool prefix>_AUTO_INSTALL[.code] variables, ex. [.code]TOFUENV_AUTO_INSTALL[.code] for OpenTofu.

[.code]tenv <tool> use[.code] command also supports the following binary version set (besides the traditional Semver 2.0.0):

  • a version constraint string (checked against versions available in TENV_ROOT directory)
  • [.code]latest[.code] or [.code]latest-pre[.code] (as described above for the [.code]install[.code] command)
  • [.code]latest-allowed[.code] or [.code]min-required[.code]: tenv will scan your IAC files to detect which version is maximally allowed or minimally required

When using [.code]latest-allowed[.code] or [.code]min-required[.code], tenv will check our IaC files to determine the version that can be used. Let’s create one to check:

terraform {
  required_version = "<= 1.5.6"
}
...
$ tenv tf use latest-allowed
Scan project to find .tf files
Found compatible version installed locally : 1.5.6
Written 1.5.6 in /Users/tofuutils/.tenv/Terraform/version

The latest allowed version of Terrraform was determined by tenv based on our version.tf file. Now, let’s use another tenv command: constraint. We can set IaC tool version constraints using tenv CLI too. This can be done via the [.code]tenv <tool> constraint[.code] command:

$ tenv tf constraint "<=1.5.4"
Written <=1.5.4 in /Users/tofuutils/.tenv/Terraform/constraint
$ tenv tf use latest-allowed
Scan project to find .tf files
No compatible version found locally, search a remote one...
Fetching all releases information from https://releases.hashicorp.com/terraform/index.json
Found compatible version remotely : 1.5.4
Installing Terraform 1.5.4
Downloading https://releases.hashicorp.com/terraform/1.5.4/terraform_1.5.4_darwin_amd64.zip
Downloading https://releases.hashicorp.com/terraform/1.5.4/terraform_1.5.4_SHA256SUMS
Downloading https://releases.hashicorp.com/terraform/1.5.4/terraform_1.5.4_SHA256SUMS.sig
Downloading https://www.hashicorp.com/.well-known/pgp-key.txt
Installation of Terraform 1.5.4 successful
Written 1.5.4 in /Users/tofuutils/.tenv/Terraform/version

After we set an additional constraint, tenv considered it while determining the latest allowed version, eventually choosing version  1.5.4 of Terraform.

Uninstall obsolete versions

tenv can also uninstall IaC tool binaries when they are no longer needed:

$ tenv tf list
  1.5.5
  1.5.6
  1.5.7
$ tenv tf uninstall 1.5.6
Uninstallation of Terraform 1.5.6 successful (directory /Users/tofuutils/.tenv/Terraform/1.5.6 removed)
$ tenv tf list           
  1.5.5
  1.5.7

Additional tenv features

1. Signature support

tenv provides signature support for verifying the integrity of binary installations of IaC tools. For OpenTofu, it verifies both the sha256 checksum and the signature of the checksum file using cosign or PGP via gopenpgp. 

However, unstable OpenTofu versions are signed only with cosign, with tenv displaying a warning if cosign is not found. 

For Terraform, tenv verifies the sha256 checksum and the PGP signature of the checksum file using gopenpgp, as no cosign signature is available. For Terragrunt and Atmos, tenv checks only the sha256 checksum, as no signatures are available for these tools.

2. Advanced remote configuration

tenv supports remote artifactory usage (like JFrog Artifactory) with flexible configuration defined in a YAML file, the path to which is passed in the [.code]TENV_REMOTE_CONF[.code] variable. 

The YAML file can have one part for each supported proxy: tofu, terraform, terragrunt, and atmos. Key settings allow controlling installation and listing behaviors, such as direct URL generation [.code](install_mode)[.code], HTML parsing for release information (list_mode)[.code], URL overrides [.code](url, list_url)[.code], and URL rewriting [.code](old_base_url, new_base_url)[.code].

Here is an example of a custom configuration where Terraform binaries will be retrieved from the mirror, as well as a list of available releases. OpenTofu binaries will be retrieved from the mirror, but available releases will be taken from the GitHub API.

tofu:
  url: "https://artifactory.example.com/artifactory/github"
  install_mode: "direct"
  list_url: "https://api.github.com/repos/opentofu/opentofu/releases"
terraform:
  url: "https://artifactory.example.com/artifactory/hashicorp"
  list_mode: "html"

More detailed description of a remote artifactory configuration can be found in the documentation.

3. Shell completion

tenv can enhance your command-line experience with shell completion. For tenv installed via Brew or Nix, shell completion is installed automatically. Additionally, it can be manually configured for ZSH, Bash, Powershell and fish.

Conclusion

tenv is a versatile IaC tools version manager that significantly reduces the overhead of managing multiple versions for different projects. It reduces time spent on binaries’ management, allowing you to focus on code development while keeping IaC tools management simple and easy. 

By the way, there are many more features tenv provides. Check out the tenv GitHub repo to find more ;) 

If you want to see more detailed articles on tenv usage, please let us know.  

– Your tofuutils team

About us

We are tofuutils, a dedicated team of developers passionate about creating modern, efficient tools for streamlining Infrastructure-as-Code (IaC) management. 

Our flagship project, tenv, is an open-source solution designed to simplify version management for key IaC tools like Terraform, OpenTofu, Terragrunt, and Atmos. 

We strive to provide powerful and flexible tools to enhance the development workflow, which is why we’ve made tenv fast and adaptable, for seamless integration into your day-to-day work.

Our tofuutils team, who’s been working on tenv and tofuenv development (Alexander Sharov, Denis Vaumoron, Nikolay Mishin, and Anastasiia Kozlova) believe that tenv will help developers and DevOps to stop struggling with and spending time on IaC tools management, and we’re excited to help!

Introduction

Infrastructure-as-Code (IaC) is a widely used approach to managing and provisioning infrastructure. It’s a constantly changing field: the list of IaC tools is always growing, not to mention that each tool is being actively developed, releasing new features, enhancements, and bug fixes at least once a week.

However, keeping track of all these changes can be complicated, especially when it comes to managing different versions of IaC tools. With multiple projects, it can quickly become a nightmare. Each project might require a specific version of the IaC tool or its dependencies, leading to potential conflicts and compatibility issues.

Moreover, with the release of OpenTofu, most of us may need to use both it and Terraform, and perhaps some other Terraform wrappers such as Terragrunt; having to track several tools becomes a constant headache.

The solution

A dedicated version manager able to manage those tools and their versions, handle their installation, and control versions in each project even if you have a thousand of them 🥵 would be really convenient, right? The answer is right here – tenv.

tenv is a version manager for Terraform, OpenTofu, Terragrunt, and Atmos, written in Go. This versatile version manager simplifies the complexity of version control, helping you avoid spending time on IaC tools’ version management and ensuring developers and DevOps can focus on what matters most: crafting innovative products and driving business value.

tenv main features

tenv has the following key features:

  • Versatile version management: currently supports managing four main IaC tools: Terraform, OpenTofu, Terragrunt, and Atmos.
  • Signature verification: supports cosign and PGP.
  • Intuitive installation: simple installation process with Homebrew and manual options.
  • Semver 2.0.0 compatibility: can extract required version constraints from OpenTofu/Terraform/Terragrunt files.
  • Backwards compatibility: supports versions files used by tfenv and tofuenv tools (.terraform-version and .opentofu-version, accordingly).  

What makes tenv unique

tenv is a version management tool specifically tailored for managing Terraform, OpenTofu, Terragrunt and Atmos. 

Unlike tools such as asdf, tfenv, and tofuenv, tenv is distributed as binaries, making it OS-independent. This distribution method enhances tool performance, providing the Go-based tenv with greater efficiency and flexibility. At this moment, tenv is available for all major operating systems such as MacOS, Windows, Linux, BSD, and Solaris.

While tenv shares similar goals with tfswitch, a solid tool for Terraform version management, it stands out by supporting a broader range of tools, including OpenTofu, Terragrunt, and Atmos. 

tenv is designed with unique features for each of these tools, enabling seamless project management and smooth migration between them. Coupled with active and thorough development, tenv offers a robust solution for managing multiple IaC tool versions efficiently.

Moveover, if you’re already using asdf and want to try tenv without the overhead of an additional tool installation, tenv offers an official plugin.

Getting started

Install tenv

tenv can be installed on all modern operating systems: MacOS, Ubuntu, Arch Linux, BSD and Windows. To simplify the installation process, all popular package managers are supported: brew, chocolatey, nix, yay, apk, snap and several others. Let’s look at some of them below:

You can use brew to install tenv in MacOS environment:

$ brew install tenv

You can use choco to install tenv to Windows environment:

$ choco install tenv

More detailed installation instructions can be found in the GitHub repo.

A manual installation of the packaged binaries is also available. Simply download a binary suitable for your OS (.deb, .rpm, .apk, pkg.tar.zst , .zip or .tar.gz format) by visiting the release page. After downloading, unzip the folder and seamlessly integrate it into your system's PATH.

Finally, tenv can be run in a CI pipeline using a prebuilt Docker image:

$ docker run -it --rm tofuutils/tenv:latest help

After the installation, your tenv version can be checked via [.code]version[.code] command:

$ tenv version
tenv version v1.6.2

How it works

tenv is designed to seamlessly support OpenTofu, Terraform, Terragrunt, and Atmos. All tools can be managed via [.code]tenv <tool> <command>[.code], where tool (alias) is:

Alias Env vars prefix Tool
tf TFENV Terraform
tofu TOFUENV OpenTofu
tg TG Terragrunt
atmos ATMOS Atmos

tenv is distributed as a set of binaries. The tenv binary acts as a proxy, calling the specific tool’s binary (e.g., terraform/tofu/terragrunt/atmos), based on the subcommand passed down from the table above.

Using tenv

The list of commands for each tool can be checked with [.code]help[.code] command. Let’s check for Terraform (tf):

$ tenv tf help
Subcommand to manage several versions of Terraform (https://www.terraform.io).
Usage:
  tenv tf [command]
Aliases:
  tf, terraform
Available Commands:
  constraint  Set a default constraint expression for Terraform.
  detect      Display Terraform current version.
  install     Install a specific version of Terraform.
  list        List installed Terraform versions.
  list-remote List installable Terraform versions.
  reset       Reset used version of Terraform.
  uninstall   Uninstall a specific version of Terraform.
  use         Switch the default Terraform version to use.
Flags:
  -h, --help   help for tf
Global Flags:
  -q, --quiet              no unnecessary output (and no log)
  -r, --root-path string   local path to install versions of OpenTofu, Terraform and Terragrunt
  -v, --verbose            verbose output (and set log level to Trace)
Use "tenv tf [command] --help" for more information about a command.

Alternatively, an alias for tf - terraform - can be used:

$ tenv terraform help

In the same way, we can get info about the command available for OpenTofu (tofu, opentofu) and Terragrunt (tg, terragrunt) management.

Now, let’s explore the functionality tenv provides.

Install IaC tool

To install OpenTofu, Terraform, Terragrunt or Atmos, we need to run the install command with a required tool name/alias. Let’s install OpenTofu as example:

$ tenv tofu install
No version files found for OpenTofu, fallback to latest strategy
Fetching all releases information from https://api.github.com/repos/opentofu/opentofu/releases
Found compatible version remotely : 1.6.2
Installing OpenTofu 1.6.2
Fetching release information from https://api.github.com/repos/opentofu/opentofu/releases/tags/v1.6.2
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.2/tofu_1.6.2_darwin_amd64.zip
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.2/tofu_1.6.2_SHA256SUMS
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.2/tofu_1.6.2_SHA256SUMS.sig
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.2/tofu_1.6.2_SHA256SUMS.pem
cosign executable not found, fallback to pgp check
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.2/tofu_1.6.2_SHA256SUMS.gpgsig
Downloading https://get.opentofu.org/opentofu.asc
Installation of OpenTofu 1.6.2 successful

By default, the latest version is downloaded. However, a specific version of the IaC tool can also be installed when needed. Let’s try to install version 1.5.7 of Terraform:

$ tenv tf install 1.5.7
Installing Terraform 1.5.7
Fetching release information from https://releases.hashicorp.com/terraform/1.5.7/index.json
Downloading https://releases.hashicorp.com/terraform/1.5.7/terraform_1.5.7_darwin_amd64.zip
Downloading https://releases.hashicorp.com/terraform/1.5.7/terraform_1.5.7_SHA256SUMS
Downloading https://releases.hashicorp.com/terraform/1.5.7/terraform_1.5.7_SHA256SUMS.sig
Downloading https://www.hashicorp.com/.well-known/pgp-key.txt
Installation of Terraform 1.5.7 successful

The install command also supports version constraints such as:

  • latest - the latest available stable version
  • latest-pre - the latest available version, including unstable ones
  • latest-allowed or min-required - tenv will scan our IaC tools’ files to detect which version is maximally allowed or minimally required. 

Let’s use latest-pre to install the latest available version of OpenTofu:

$ tenv tofu install latest-pre  
Fetching all releases information from https://api.github.com/repos/opentofu/opentofu/releases
Found compatible version remotely : 1.7.0-alpha1
Installing OpenTofu 1.7.0-alpha1
Fetching release information from https://api.github.com/repos/opentofu/opentofu/releases/tags/v1.7.0-alpha1
Downloading https://github.com/opentofu/opentofu/releases/download/v1.7.0-alpha1/tofu_1.7.0-alpha1_darwin_amd64.zip
Downloading https://github.com/opentofu/opentofu/releases/download/v1.7.0-alpha1/tofu_1.7.0-alpha1_SHA256SUMS
Downloading https://github.com/opentofu/opentofu/releases/download/v1.7.0-alpha1/tofu_1.7.0-alpha1_SHA256SUMS.sig
Downloading https://github.com/opentofu/opentofu/releases/download/v1.7.0-alpha1/tofu_1.7.0-alpha1_SHA256SUMS.pem
skip signature check : cosign executable not found and pgp check not available for unstable version
Installation of OpenTofu 1.7.0-alpha1 successful

We can also use the [.code]-q (--quiet)[.code] flag to have no logs/only important ones printed to the output.

$ tenv tofu install 1.6.0 -q

However, it would be good to know which versions of the tools are available for installation before choosing one. Luckily, tenv can help with this too!

List IaC tool versions

First, tenv has a command list-remote, which provides you with a list of all IaC tool versions available for installation. Let’s try to get one for Terragrunt (some versions in the middle have been omitted):

$ tenv tg list-remote
Fetching all releases information from https://api.github.com/repos/gruntwork-io/terragrunt/releases
0.0.4
0.0.5
0.0.6
0.0.7
0.0.8
0.0.9
0.0.10
0.0.11
0.1.0
0.55.21
0.56.0
0.56.1
0.56.2

Similarly, tenv can help to check the list of IaC tool versions already installed locally (shown here for OpenTofu):

$ tenv tofu list            
  1.6.0
  1.6.2
  1.7.0-alpha1

Automatic version management for IaC tool

tenv has the [.code]detect[.code] command that returns the version of the tool binary used for the current project. The tool version resolution is not straightforward, since the version can be set in several places. 

Let’s explore this example of version resolution for Terraform. The extended list of  IaC tools be found in tenv repo docs.

tenv checks Terraform version in the following order:

  • [.code]TFENV_TERRAFORM_VERSION[.code] environment variable
  • .terraform-version file
  • .tfswitchrc file
  • [.code]terraform_version_constraint[.code] from terragrunt.hcl file
  • [.code]terraform_version_constraint[.code] from terragrunt.hcl.json file
  • [.code]TFENV_TERRAFORM_DEFAULT_VERSION[.code] environment variable
  • ${TENV_ROOT}/Terraform/version file (can be written with tenv tf use)
  • latest-allowed

If no versions are found in the list above, the latest available stable version will be used by tenv.

While environment variables from the list above can be set manually, let’s focus on the version files. 

There is a list of version files supported by tenv for different tools. A version file should be placed in the working directory, one of its parent directories, or user home directory (in which case tenv detects it and uses that version). 

Thus, using proper version files in different projects allows you to switch versions automatically without running any additional commands.

tenv supports the following version files:

  • .opentofu-version - Opentofu version file. tenv will detect and use the version written in it
  • .terraform-version or .tfswitchrc - Terraform version file. tenv will detect and use the version written in it
  • .terragrunt-version or .tgswitchrc - Terragrunt version file. tenv will detect and use the version written in it
  • terragrunt.hcl or terragrunt.hcl.json - tenv will read constraint from the [.code]terraform_version_constraint[.code] or [.code]terragrunt_version_constraint[.code] field in it (depending on the proxy or subcommand used)
  • .atmos-version - Atmos version file. tenv will detect and use the version written in it
  • .tf or .tf.json IaC files - tenv will use version constraints from there when using the latest-allowed or min-required strategies

Let’s try it out with OpenTofu. First, we don’t set any specific versions.

$ tenv tofu detect
No version files found for OpenTofu, fallback to latest-allowed strategy
Scan project to find .tf files
No OpenTofu version requirement found in project files, fallback to latest strategy
Found compatible version installed locally : 1.6.2
OpenTofu 1.6.2 will be run from this directory.

No version set was found, so the latest stable one is used by default. Now let’s set the [.code]TOFUENV_TOFU_DEFAULT_VERSION[.code] variable to 1.6.0.

$ tenv tofu detect                         
Resolved version from TOFUENV_TOFU_DEFAULT_VERSION : 1.6.0
OpenTofu 1.6.0 already installed
OpenTofu 1.6.0 will be run from this directory.

In this case, tenv found a specific version set, so now our project will use this one instead of the latest 1.6.1. 

However, in some cases we may have projects already using a newer version, but we want to keep the default one to be 1.6.0. We can create an .opentofu-version file in our project’s directory and specify the version there.

$ echo 1.6.1 > .opentofu-version
$ tenv tofu detect              
Resolved version from .opentofu-version : 1.6.1
Installing OpenTofu 1.6.1
Fetching release information from https://api.github.com/repos/opentofu/opentofu/releases/tags/v1.6.1
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.1/tofu_1.6.1_darwin_amd64.zip
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.1/tofu_1.6.1_SHA256SUMS
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.1/tofu_1.6.1_SHA256SUMS.sig
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.1/tofu_1.6.1_SHA256SUMS.pem
cosign executable not found, fallback to pgp check
Downloading https://github.com/opentofu/opentofu/releases/download/v1.6.1/tofu_1.6.1_SHA256SUMS.gpgsig
Downloading https://get.opentofu.org/opentofu.asc
Installation of OpenTofu 1.6.1 successful
OpenTofu 1.6.1 will be run from this directory.
$ cd ..
$ tenv tofu detect
Resolved version from TOFUENV_TOFU_DEFAULT_VERSION : 1.6.0
OpenTofu 1.6.0 already installed
OpenTofu 1.6.0 will be run from this directory.

After setting the 1.6.1 version of OpenTofu in the version file, tenv detected this version instead of 1.6.0, set in the [.code]TOFUENV_TOFU_DEFAULT_VERSION[.code] variable.

If the Opentofu binary for this version is not present, tenv will install it. 

However, after changing the working directory to one level above, tenv detected the 1.6.0 OpenTofu version again, since no .opentofu-version file was presented in that path or in any parent directory, nor in a user’s home directory. The version from the [.code]environment[.code] variable was used instead.

Use specific version

tenv also has a [.code]tenv <tool> use[.code] command which allows you to manually choose the version of the tool you currently want to use. This version is written to the [.code]TENV_ROOT/<TOOL>/version[.code] file. Let’s try with Terraform:

$ tenv tf use 1.5.6
Installing Terraform 1.5.6
Fetching release information from https://releases.hashicorp.com/terraform/1.5.6/index.json
Downloading https://releases.hashicorp.com/terraform/1.5.6/terraform_1.5.6_darwin_amd64.zip
Downloading https://releases.hashicorp.com/terraform/1.5.6/terraform_1.5.6_SHA256SUMS
Downloading https://releases.hashicorp.com/terraform/1.5.6/terraform_1.5.6_SHA256SUMS.sig
Downloading https://www.hashicorp.com/.well-known/pgp-key.txt
Installation of Terraform 1.5.6 successful
Written 1.5.6 in /Users/tofuutils/.tenv/Terraform/version

Version 1.5.6 of Terraform was set to use. Same as for the [.code]detect[.code] command – if no binary is found for the version specified, it will be installed by tenv automatically. 

The [.code]TENV_ROOT/<TOOL>/version[.code] can be removed via the [.code]tenv <tool> reset[.code] command.

$ tenv tofu use 1.6.1             
Written 1.6.1 in /Users/tofuutils/.tenv/OpenTofu/version
$ ls ~/.tenv/OpenTofu/version 
/Users/tofuutils/.tenv/OpenTofu/version
$ cat ~/.tenv/OpenTofu/version 
1.6.1
$ tenv tofu reset
Removed /Users/tofuutils/.tenv/OpenTofu/version
$ cat ~/.tenv/OpenTofu/version
cat: /Users/tofuutils/.tenv/OpenTofu/version: No such file or directory

If we want to change the default behavior and disable the automatic installation, we can set the variable [.code]TENV_AUTO_INSTALL[.code] to [.code]false[.code].

$ export TENV_AUTO_INSTALL=false
$ tenv tf use 1.5.4             
Written 1.5.4 in /Users/tofuutils/.tenv/Terraform/version
$ terraform init
Failure during terraform call : fork/exec /Users/tofuutils/.tenv/Terraform/1.5.4/terraform: no such file or directory

As you can see, Terraform version in use was changed to 1.5.4, but since no installation occurred by default, and this version was not installed before, we got an error when trying to run terraform.

Auto installation property can also be controlled for a specific tool only, i.e., [.code]<tool prefix>_AUTO_INSTALL[.code] variables, ex. [.code]TOFUENV_AUTO_INSTALL[.code] for OpenTofu.

[.code]tenv <tool> use[.code] command also supports the following binary version set (besides the traditional Semver 2.0.0):

  • a version constraint string (checked against versions available in TENV_ROOT directory)
  • [.code]latest[.code] or [.code]latest-pre[.code] (as described above for the [.code]install[.code] command)
  • [.code]latest-allowed[.code] or [.code]min-required[.code]: tenv will scan your IAC files to detect which version is maximally allowed or minimally required

When using [.code]latest-allowed[.code] or [.code]min-required[.code], tenv will check our IaC files to determine the version that can be used. Let’s create one to check:

terraform {
  required_version = "<= 1.5.6"
}
...
$ tenv tf use latest-allowed
Scan project to find .tf files
Found compatible version installed locally : 1.5.6
Written 1.5.6 in /Users/tofuutils/.tenv/Terraform/version

The latest allowed version of Terrraform was determined by tenv based on our version.tf file. Now, let’s use another tenv command: constraint. We can set IaC tool version constraints using tenv CLI too. This can be done via the [.code]tenv <tool> constraint[.code] command:

$ tenv tf constraint "<=1.5.4"
Written <=1.5.4 in /Users/tofuutils/.tenv/Terraform/constraint
$ tenv tf use latest-allowed
Scan project to find .tf files
No compatible version found locally, search a remote one...
Fetching all releases information from https://releases.hashicorp.com/terraform/index.json
Found compatible version remotely : 1.5.4
Installing Terraform 1.5.4
Downloading https://releases.hashicorp.com/terraform/1.5.4/terraform_1.5.4_darwin_amd64.zip
Downloading https://releases.hashicorp.com/terraform/1.5.4/terraform_1.5.4_SHA256SUMS
Downloading https://releases.hashicorp.com/terraform/1.5.4/terraform_1.5.4_SHA256SUMS.sig
Downloading https://www.hashicorp.com/.well-known/pgp-key.txt
Installation of Terraform 1.5.4 successful
Written 1.5.4 in /Users/tofuutils/.tenv/Terraform/version

After we set an additional constraint, tenv considered it while determining the latest allowed version, eventually choosing version  1.5.4 of Terraform.

Uninstall obsolete versions

tenv can also uninstall IaC tool binaries when they are no longer needed:

$ tenv tf list
  1.5.5
  1.5.6
  1.5.7
$ tenv tf uninstall 1.5.6
Uninstallation of Terraform 1.5.6 successful (directory /Users/tofuutils/.tenv/Terraform/1.5.6 removed)
$ tenv tf list           
  1.5.5
  1.5.7

Additional tenv features

1. Signature support

tenv provides signature support for verifying the integrity of binary installations of IaC tools. For OpenTofu, it verifies both the sha256 checksum and the signature of the checksum file using cosign or PGP via gopenpgp. 

However, unstable OpenTofu versions are signed only with cosign, with tenv displaying a warning if cosign is not found. 

For Terraform, tenv verifies the sha256 checksum and the PGP signature of the checksum file using gopenpgp, as no cosign signature is available. For Terragrunt and Atmos, tenv checks only the sha256 checksum, as no signatures are available for these tools.

2. Advanced remote configuration

tenv supports remote artifactory usage (like JFrog Artifactory) with flexible configuration defined in a YAML file, the path to which is passed in the [.code]TENV_REMOTE_CONF[.code] variable. 

The YAML file can have one part for each supported proxy: tofu, terraform, terragrunt, and atmos. Key settings allow controlling installation and listing behaviors, such as direct URL generation [.code](install_mode)[.code], HTML parsing for release information (list_mode)[.code], URL overrides [.code](url, list_url)[.code], and URL rewriting [.code](old_base_url, new_base_url)[.code].

Here is an example of a custom configuration where Terraform binaries will be retrieved from the mirror, as well as a list of available releases. OpenTofu binaries will be retrieved from the mirror, but available releases will be taken from the GitHub API.

tofu:
  url: "https://artifactory.example.com/artifactory/github"
  install_mode: "direct"
  list_url: "https://api.github.com/repos/opentofu/opentofu/releases"
terraform:
  url: "https://artifactory.example.com/artifactory/hashicorp"
  list_mode: "html"

More detailed description of a remote artifactory configuration can be found in the documentation.

3. Shell completion

tenv can enhance your command-line experience with shell completion. For tenv installed via Brew or Nix, shell completion is installed automatically. Additionally, it can be manually configured for ZSH, Bash, Powershell and fish.

Conclusion

tenv is a versatile IaC tools version manager that significantly reduces the overhead of managing multiple versions for different projects. It reduces time spent on binaries’ management, allowing you to focus on code development while keeping IaC tools management simple and easy. 

By the way, there are many more features tenv provides. Check out the tenv GitHub repo to find more ;) 

If you want to see more detailed articles on tenv usage, please let us know.  

– Your tofuutils team

Logo Podcast
With special guest
John Willis

Schedule a technical demo. See env0 in action.

Footer Illustration