Tenv helps you install and switch versions of OpenTofu/Terraform, Terragrunt, and Atmos with simple commands.
Tenv is a version manager designed to simplify the installation and management of OpenTofu/Terraform, Terragrunt, and Atmos. It allows users to switch between different versions of these tools effortlessly using simple commands.
Key Features:
Versatile Version Management: Seamlessly install and switch between various versions of OpenTofu/Terraform, Terragrunt, and Atmos.
Semver 2.0.0 Compatibility: Utilizes HCL parsing to handle version constraints, ensuring compatibility with semantic versioning standards.
Signature Verification: Enhances security by supporting cosign for checksum verification, providing an additional layer of trust in the tools you use.
Cross-Platform Support: Works uniformly across Linux, macOS, Windows, and other modern operating systems, ensuring consistent functionality regardless of your environment.
High Performance: Built with Go, Tenv offers superior performance compared to shell-based alternatives, reducing latency and improving efficiency.
Audience & Benefit:
Ideal for developers and DevOps professionals who require efficient management of multiple tool versions. By automating version switching and enhancing security through signature verification, Tenv streamlines workflow and reduces manual overhead, allowing users to focus on development tasks without worrying about tool compatibility or versioning complexities.
README
tenv
OpenTofu, Terraform, Terragrunt, Terramate and Atmos version manager, written in Go.
Welcome to tenv, a versatile version manager for OpenTofu,
Terraform, Terragrunt, Terramate and
Atmos, written in Go. Our tool simplifies the complexity of handling different versions of these powerful tools, ensuring developers and DevOps professionals can focus on what matters most - building and deploying efficiently.
Versatile version management: Easily switch between different versions of OpenTofu,
Terraform, Terragrunt, Terramate and Atmos.
Semver 2.0.0 Compatibility: Utilizes go-version for semantic versioning and use the HCL parser to extract required version constraint from OpenTofu/Terraform/Terragrunt files (see and ).
asdf-vm share the same goals than tenv : simplify the usage of several version of tools.
asdf-vm is generic and extensible with a plugin system, key tenv differences :
tenv is more specific and has features dedicated to OpenTofu, Terraform, Terragrunt, Terramate
and Atmos, like HCL parsing based detection (see Key Features).
tenv is distributed as independent binaries and does not rely on any shell or other CLI executable.
tenv does better in terms of performance and platform compatibility. It works uniformly across all modern operating systems,
including Linux, MacOS, Windows, BSD, and Solaris, whereas asdf-vm natively supports only Linux and MacOS.
tenv checks the sha256 checksum and the signature of the checksum file with cosign. Check Signature support section for getting more information about it.
tenv command compatibility: In nearly all places you can use the exact syntax that works in tfenv / tofuenv.
If you're coming from tfenv/tofuenv and comfortable with that way of working you can almost always use the same syntax with tenv.
tenv performance: It sounds incredibly useful, though it might be tough to get a real apples to apples comparison since the
tools work differently in a lot of ways. The author of asdf did a great writeup of performance problems. asdf-vm is written in bash
which certainly makes it challenging to be performant, whereas tenv is written in Golang and works much faster.
Add the following Nix code to your NixOS Configuration, usually located in /etc/nixos/configuration.nix
environment.systemPackages = [
pkgs.tenv
];
nix-shell
nix-shell -p tenv
Manual Installation
Get the most recent packaged binaries (.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.
Docker Installation
You can use dockerized version of tenv via the following command:
docker run -it --rm tofuutils/tenv:latest help
The docker container is not meant as a way to run tenv for CI pipelines, for local use, you should use one of the packaged binaries.
Install shell completion
> [!NOTE]
> If you install tenv via Brew, MacPorts, or Nix, completion will be installed automatically.
tenv completion fish > ~/.tenv.completion.fish
echo "source \$HOME/.tenv.completion.fish" >> ~/.config/fish/config.fish
Usage
tenv supports OpenTofu,
Terraform, Terragrunt, Terramate and
Atmos. To manage each binary you can use tenv . Below is a list of tools and commands that use actual subcommands:
Without subcommand tenv display interactive menus to manage tools and their versions.
tenv <tool> install [version]
Install a requested version of the tool (into TENV_ROOT directory from _REMOTE url).
Without a parameter, the version to use is resolved automatically (see resolution order in tools description, with latest as default in place of latest-allowed).
If a parameter is passed, available options include:
a version constraint string (checked against versions available in TENV_ROOT directory).
latest, latest-stable (old name of latest) or latest-pre (include unstable version), which are checked against versions available in TENV_ROOT directory.
latest: or min: to get first version matching with `` as a regexp after a descending or ascending version sort.
latest-allowed or min-required to scan your IAC files to detect which version is maximally allowed or minimally required. See required_version docs.
tenv tofu use v1.6.0-beta5
tenv tf use min-required
tenv tg use latest
tenv atmos use latest
tenv tofu use latest-allowed
tenv <tool> detect
Detect the used version of tool for the working directory.
$ 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.1
OpenTofu 1.6.1 will be run from this directory.
$ tenv tg detect -q
Terragrunt 0.55.1 will be run from this directory.
$ tenv atmos detect -q
Atmos 1.72.0 will be run from this directory.
tenv <tool> reset
Reset used version of tool (remove TENV_ROOT//version file).
$ tenv help tf detect
Display Terraform current version.
Usage:
tenv tf detect [flags]
Flags:
-a, --arch string specify arch for binaries downloading (default "amd64")
-f, --force-remote force search on versions available at TFENV_REMOTE url
-h, --help help for detect
-k, --key-file string local path to PGP public key file (replace check against remote one)
-n, --no-install disable installation of missing version
-c, --remote-conf string path to remote configuration file (advanced settings)
-u, --remote-url string remote url to install from
Global Flags:
-q, --quiet no unnecessary output (and no log)
-r, --root-path string local path to install versions of OpenTofu, Terraform and Terragrunt (default "/home/dvaumoron/.tenv")
-v, --verbose verbose output (and set log level to Trace)
$ tenv tofu use -h
Switch the default OpenTofu version to use (set in TENV_ROOT/OpenTofu/version file)
Available parameter options:
- an exact Semver 2.0.0 version string to use
- a version constraint expression (checked against version available in TENV_ROOT directory)
- latest, latest-stable or latest-pre (checked against version available in TENV_ROOT directory)
- latest-allowed or min-required to scan your OpenTofu files to detect which version is maximally allowed or minimally required.
Usage:
tenv tofu use version [flags]
Flags:
-a, --arch string specify arch for binaries downloading (default "amd64")
-f, --force-remote force search on versions available at TOFUENV_REMOTE url
-t, --github-token string GitHub token (increases GitHub REST API rate limits)
-h, --help help for use
-k, --key-file string local path to PGP public key file (replace check against remote one)
-n, --no-install disable installation of missing version
-c, --remote-conf string path to remote configuration file (advanced settings)
-u, --remote-url string remote url to install from
-w, --working-dir create .opentofu-version file in working directory
Global Flags:
-q, --quiet no unnecessary output (and no log)
-r, --root-path string local path to install versions of OpenTofu, Terraform and Terragrunt (default "/home/dvaumoron/.tenv")
-v, --verbose verbose output (and set log level to Trace)
tenv update-path
Display PATH updated with tenv directory location first. With GITHUB_ACTIONS set to true, write tenv directory location to GITHUB_PATH.
This command can be used when one of the managed tool is already installed on your system and hide the corresponding proxy (in that case which tenv and which will indicate different locations). The following shell call should resolve such issues :
String (Default: current tenv binaries architecture)
Allow to override the default architecture for binaries downloading during installation.
tenv subcommands detect, install and use support a --arch, -a flag version.
TENV_AUTO_INSTALL
String (Default: false)
If set to true tenv will automatically install missing tool versions needed.
tenv subcommands detect and use support a --install, -i enabling flag, and a --no-install, -n disabling flag.
TENV_FORCE_REMOTE
String (Default: false)
If set to true tenv detection of needed version will skip local check and verify compatibility on remote list.
tenv subcommands detect and use support a --force-remote, -f flag version.
TENV_GITHUB_TOKEN
String (Default: "")
Allow to specify a GitHub token to increase GitHub Rate limits for the REST API. Useful because OpenTofu, Terragrunt and Atmos binaries are downloaded from GitHub repository.
tenv tofu and tenv tg subcommands detect, install, list-remote and use support a --github-token, -t flag version.
TENV_QUIET
String (Default: false)
If set to true tenv disable unnecessary output (including log level forced to off).
tenv subcommands support a --quiet, -q flag version.
TENV_LOG
String (Default: "warn")
Set tenv log level (possibilities sorted by decreasing verbosity : "trace", "debug", "info", "warn", "error", "off").
tenv support a --verbose, -v flag which set log level to "trace".
tenv subcommands detect, install, list-remote and use support a --remote-conf, -c flag version.
TENV_ROOT
String (Default: ${HOME}/.tenv)
The path to a directory where the local OpenTofu versions, Terraform versions, Terragrunt versions and tenv configuration files exist.
tenv support a --root-path, -r flag version.
TENV_SKIP_LAST_USE
String (Default: false)
If set to true tenv disable tracking of last use date for installed versions. It allow to avoid warning message when tenv is installed as root user and run with a normal user by skipping the writing of last-use.txt. This will lead to misselection with not-used-for and not-used-since behavior of tenv uninstall.
TENV_VALIDATION
String (Default: signature)
Set tenv validation, known values are "signature" (check SHA256 and its signature, see signature support), "sha" (only check SHA256), "none" (no validation).
GITHUB_ACTIONS
String (Default: false)
If set to true tenv proxies exposes proxied output stdout, stderr, and exitcode by writing them into GITHUB_OUTPUT in multiline format. GitHub Actions set it (see default environment variables).
GITHUB_OUTPUT
String (Default: "")
Needed when GITHUB_ACTIONS is set to true, path to a file to write proxied output.
GITHUB_PATH
String (Default: "")
Used by tenv update-path when GITHUB_ACTIONS is set to true, path to a file to write tenv directory location.
OpenTofu environment variables
TOFUENV_AGNOSTIC_PROXY
String (Default: false)
Switch tofu proxy to an agnostic proxy (behave like tf, see resolution order).
Allow to specify a local file path or URL to OpenTofu PGP public key. If a URL is provided (starting with "http://" or "https://"), the key will be downloaded from that URL. If a local file path is provided, the key will be read from that location. If not set, the key will be downloaded from the default URL (https://get.opentofu.org/opentofu.asc).
tenv tofu subcommands detect, ìnstall and use support a --key-file, -k flag version.
URL to install OpenTofu, when TOFUENV_REMOTE differ from its default value, TOFUENV_INSTALL_MODE is set to "direct" and TOFUENV_LIST_MODE is set to "html" (assume an artifact proxy usage).
tenv tofu subcommands detect, install, list-remote and use support a --remote-url, -u flag version.
Could be used with TOFUENV_REMOTE_USER to specify HTTP basic auth when same credential are used with TOFUENV_REMOTE and TOFUENV_LIST_URL (instead of https://user:password@host.org URL format).
TOFUENV_REMOTE_USER
String (Default: "")
Could be used with TOFUENV_REMOTE_PASSWORD to specify HTTP basic auth when same credential are used with TOFUENV_REMOTE and TOFUENV_LIST_URL (instead of https://user:password@host.org URL format).
Same as TENV_AUTO_INSTALL (compatibility with tfenv).
TFENV_FORCE_REMOTE
Same as TENV_FORCE_REMOTE.
TFENV_HASHICORP_PGP_KEY
Allow to specify a local file path or URL to Hashicorp PGP public key. If a URL is provided (starting with "http://" or "https://"), the key will be downloaded from that URL. If a local file path is provided, the key will be read from that location. If not set, the key will be downloaded from the default URL (https://www.hashicorp.com/.well-known/pgp-key.txt).
tenv tf subcommands detect, ìnstall and use support a --key-file, -k flag version.
TFENV_INSTALL_MODE
String (Default: "api")
"api" install mode retrieve download url of Terraform from Hashicorp Release API (TFENV_REMOTE must comply with it).
"direct" install mode generate download url of Terraform based on TFENV_REMOTE.
URL to install Terraform, changing it assume an artifact proxy use (TFENV_LIST_URL copy it, and if it differ from its default value, TFENV_LIST_MODE is set to "html", because an artifact proxy usage will not disturb the retrieving of index.json for a release, but will freeze the json list of releases).
tenv tf subcommands detect, install, list-remote and use support a --remote-url, -u flag version.
Could be used with TFENV_REMOTE_USER to specify HTTP basic auth when same credential are used with TFENV_REMOTE and TFENV_LIST_URL (instead of https://user:password@host.org URL format).
TFENV_REMOTE_USER
String (Default: "")
Could be used with TFENV_REMOTE_PASSWORD to specify HTTP basic auth when same credential are used with TFENV_REMOTE and TFENV_LIST_URL (instead of https://user:password@host.org URL format).
If not empty string, this variable overrides Terraform default constraint, specified in ${TENV_ROOT}/Terraform/constraint file.
TFENV_TERRAFORM_DEFAULT_VERSION
String (Default: "")
If not empty string, this variable overrides Terraform fallback version, specified in ${TENV_ROOT}/Terraform/version file.
TFENV_TERRAFORM_VERSION
String (Default: "")
If not empty string, this variable overrides Terraform version, specified in .terraform-version files.
tenv tf subcommands install and detect also respects this variable.
e.g. with :
$ terraform version
Terraform v1.7.2
on linux_amd64
then :
$ TFENV_TERRAFORM_VERSION=1.7.0 terraform version
Terraform v1.7.0
on linux_amd64
Your version of Terraform is out of date! The latest version
is 1.7.2. You can update by downloading from https://www.terraform.io/downloads.html
Terragrunt environment variables
TG_INSTALL_MODE
String (the default depend on TG_REMOTE, without change on it, it is "api" else it is "direct")
"api" install mode retrieve download url of Terragrunt from Github REST API (TG_REMOTE must comply with it).
"direct" install mode generate download url of Terragrunt based on TG_REMOTE.
URL to install Terragrunt, when TG_REMOTE differ from its default value, TG_INSTALL_MODE is set to "direct" and TG_LIST_MODE is set to "html" (assume an artifact proxy usage).
tenv tg subcommands detect, install, list-remote and use support a --remote-url, -u flag version.
Could be used with TG_REMOTE_USER to specify HTTP basic auth when same credential are used with TG_REMOTE and TG_LIST_URL (instead of https://user:password@host.org URL format).
TG_REMOTE_USER
String (Default: "")
Could be used with TG_REMOTE_PASSWORD to specify HTTP basic auth when same credential are used with TG_REMOTE and TG_LIST_URL (instead of https://user:password@host.org URL format).
TG_DEFAULT_CONSTRAINT
String (Default: "")
If not empty string, this variable overrides Terragrunt default constraint, specified in ${TENV_ROOT}/Terragrunt/constraint file.
TG_DEFAULT_VERSION
String (Default: "")
If not empty string, this variable overrides Terragrunt fallback version, specified in ${TENV_ROOT}/Terragrunt/version file.
TG_VERSION
String (Default: "")
If not empty string, this variable overrides Terragrunt version, specified in .terragrunt-version files.
tenv tg subcommands install and detect also respects this variable.
e.g. with :
$ terragrunt -v
terragrunt version v0.55.1
then :
$ TG_VERSION=0.54.1 terragrunt -v
terragrunt version v0.54.1
Terramate environment variables
TM_INSTALL_MODE
String (the default depend on TM_REMOTE, without change on it, it is "api" else it is "direct")
"api" install mode retrieve download url of Terramate from Github REST API (TM_REMOTE must comply with it).
"direct" install mode generate download url of Terramate based on TM_REMOTE.
URL to install Terramate, when TM_REMOTE differ from its default value, TM_INSTALL_MODE is set to "direct" and TM_LIST_MODE is set to "html" (assume an artifact proxy usage).
tenv tm subcommands detect, install, list-remote and use support a --remote-url, -u flag version.
Could be used with TM_REMOTE_USER to specify HTTP basic auth when same credential are used with TM_REMOTE and TM_LIST_URL (instead of https://user:password@host.org URL format).
TM_REMOTE_USER
String (Default: "")
Could be used with TM_REMOTE_PASSWORD to specify HTTP basic auth when same credential are used with TM_REMOTE and TM_LIST_URL (instead of https://user:password@host.org URL format).
TM_DEFAULT_CONSTRAINT
String (Default: "")
If not empty string, this variable overrides Terramate default constraint, specified in ${TENV_ROOT}/Terramate/constraint file.
TM_DEFAULT_VERSION
String (Default: "")
If not empty string, this variable overrides Terramate fallback version, specified in ${TENV_ROOT}/Terramate/version file.
TM_VERSION
String (Default: "")
If not empty string, this variable overrides Terramate version, specified in .terramate-version files.
tenv tm subcommands install and detect also respects this variable.
e.g. with :
$ terramate version
0.13.0
then :
$ TM_VERSION=0.12.0 terramate version
0.12.0
Atmos environment variables
ATMOS_INSTALL_MODE
String (the default depend on ATMOS_REMOTE, without change on it, it is "api" else it is "direct")
"api" install mode retrieve download url of Atmos from Github REST API (ATMOS_REMOTE must comply with it).
"direct" install mode generate download url of Atmos based on ATMOS_REMOTE.
URL to install Atmos when ATMOS_REMOTE differ from its default value, ATMOS_INSTALL_MODE is set to "direct" and ATMOS_LIST_MODE is set to "html" (assume an artifact proxy usage).
tenv atmos subcommands detect, install, list-remote and use support a --remote-url, -u flag version.
Could be used with ATMOS_REMOTE_USER to specify HTTP basic auth when same credential are used with ATMOS_REMOTE and ATMOS_LIST_URL (instead of https://user:password@host.org URL format).
ATMOS_REMOTE_USER
String (Default: "")
Could be used with ATMOS_REMOTE_PASSWORD to specify HTTP basic auth when same credential are used with ATMOS_REMOTE and ATMOS_LIST_URL (instead of https://user:password@host.org URL format).
ATMOS_DEFAULT_CONSTRAINT
String (Default: "")
If not empty string, this variable overrides Atmos default constraint, specified in ${TENV_ROOT}/Atmos/constraint file.
ATMOS_DEFAULT_VERSION
String (Default: "")
If not empty string, this variable overrides Atmos fallback version, specified in ${TENV_ROOT}/Atmos/version file.
ATMOS_VERSION
String (Default: "")
If not empty string, this variable overrides Atmos version, specified in .atmos-version files.
tenv atmos subcommands install and detect also respects this variable.
e.g. with :
$ atmos version
👽 Atmos v1.72.0 on linux/amd64
then :
$ ATMOS_VERSION=1.70 atmos version
👽 Atmos v1.70.0 on linux/amd64
version files
default version file
The TENV_ROOT//version file is the tool default version used when no project specific or user specific are found. It can be written with tenv use.
opentofu version files
If you put a .opentofu-version file in the working directory, one of its parent directory, or user home directory, tenv detects it and uses the version written in it.
Note, that TOFUENV_TOFU_VERSION can be used to override version specified by .opentofu-version file.
If you put a .terraform-version or .tfswitchrc file in the working directory, one of its parent directory, or user home directory, tenv detects it and uses the version written in it.
Note, that TFENV_TERRAFORM_VERSION can be used to override version specified by those files.
If you put a .terragrunt-version or a .tgswitchrc file in the working directory, one of its parent directory, or user home directory, tenv detects it and uses the version written in it. tenv also detect a version field in a .tgswitch.toml in same places.
Note, that TG_VERSION can be used to override version specified by those files.
Recognize same values as tenv tg use command.
terragrunt.hcl or root.hcl file
Terragrunt now recommends using root.hcl instead of terragrunt.hcl as the root configuration file name.
If a terragrunt.hcl, root.hcl, or their .json equivalents exist in the working directory, a parent directory, or the user home directory, tenv will read constraints from the terraform_version_constraint or terragrunt_version_constraint field (depending on proxy or subcommand used).
If both root.hcl and terragrunt.hcl (or their .json versions) are present, terragrunt.hcl takes precedence.
terramate version files
If you put a .terramate-version file in the working directory, one of its parent directory, or user home directory, tenv detects it and uses the version written in it.
Note, that TM_VERSION can be used to override version specified by those files.
Recognize same values as tenv tm use command.
atmos version files
If you put a .atmos-version file in the working directory, one of its parent directory, or user home directory, tenv detects it and uses the version written in it.
Note, that ATMOS_VERSION can be used to override version specified by those files.
Recognize same values as tenv atmos use command.
required_version
the latest-allowed or min-required strategies scan through your IAC files (see list in project binaries) and identify a version conforming to the constraint in the relevant files. They fallback to latest when no IAC files and no default constraint are found, and can optionally be used with a default constraint as detailed in project binaries.
terraform_version_constraint from terragrunt.hcl file
terraform_version_constraint from terragrunt.hcl.json file
terraform_version_constraint from root.hcl file
terraform_version_constraint from root.hcl.json file
TOFUENV_TOFU_DEFAULT_VERSION environment variable
${TENV_ROOT}/OpenTofu/version file (can be written with tenv tofu use)
latest-allowed
The latest-allowed strategy rely on required_version from .tofu, .tofu.json, .tf or .tf.json files with a fallback to latest when no constraint are found. Moreover it is possible to add a default constraint with TOFUENV_TOFU_DEFAULT_CONSTRAINT environment variable or ${TENV_ROOT}/OpenTofu/constraint file (can be written with tenv tofu constraint). The default constraint is added while using latest-allowed, min-required or custom constraint. A default constraint with latest-allowed or min-required will avoid the fallback to latest when there is no .tf or .tf.json files.
terraform
The terraform command in this project is a proxy to HashiCorp's terraform command managed by tenv.
${TENV_ROOT}/Terraform/version file (can be written with tenv tf use)
latest-allowed
The latest-allowed strategy rely on required_version from .tf or .tf.json files with a fallback to latest when no constraint are found. Moreover it is possible to add a default constraint with TFENV_TERRAFORM_DEFAULT_CONSTRAINT environment variable or ${TENV_ROOT}/Terraform/constraint file (can be written with tenv tf constraint). The default constraint is added while using latest-allowed, min-required or custom constraint. A default constraint with latest-allowed or min-required will avoid the fallback to latest when there is no .tf or .tf.json files.
terragrunt
The terragrunt command in this project is a proxy to Gruntwork's terragrunt command managed by tenv.
terragrunt_version_constraint from terragrunt.hcl file
terragrunt_version_constraint from terragrunt.hcl.json file
terragrunt_version_constraint from root.hcl file
terragrunt_version_constraint from root.hcl.json file
TG_DEFAULT_VERSION environment variable
${TENV_ROOT}/Terragrunt/version file (can be written with tenv tg use)
latest-allowed
The latest-allowed strategy has no information for Terragrunt and will fallback to latest unless there is default constraint. Adding a default constraint could be done with TG_DEFAULT_CONSTRAINT environment variable or ${TENV_ROOT}/Terragrunt/constraint file (can be written with tenv tg constraint). The default constraint is added while using latest-allowed, min-required or custom constraint. A default constraint with latest-allowed or min-required will avoid there fallback to latest.
terramate
The terramate command in this project is a proxy to Terramate's terramate command managed by tenv.
The version resolution order is :
TM_VERSION environment variable
.terramate-version file
TM_DEFAULT_VERSION environment variable
${TENV_ROOT}/Terramate/version file (can be written with tenv tm use)
latest-allowed
The latest-allowed strategy has no information for Terramate and will fallback to latest unless there is default constraint. Adding a default constraint could be done with TM_DEFAULT_CONSTRAINT environment variable or ${TENV_ROOT}/Terramate/constraint file (can be written with tenv tm constraint). The default constraint is added while using latest-allowed, min-required or custom constraint. A default constraint with latest-allowed or min-required will avoid there fallback to latest.
atmos
The atmos command in this project is a proxy to Cloudposse's atmos command managed by tenv.
${TENV_ROOT}/Atmos/version file (can be written with tenv atmos use)
latest-allowed
The latest-allowed strategy has no information for Atmos and will fallback to latest
unless there is default constraint. Adding a default constraint could be done with
ATMOS_DEFAULT_CONSTRAINT environment variable or ${TENV_ROOT}/Atmos/constraint file (can
be written with tenv atmos constraint). The default constraint is added while using latest-allowed, min-required or custom constraint. A default constraint with latest-allowed or min-required will avoid there fallback to latest.
tf
The tf command is a proxy to tofu or terraform depending on the version files present in project.
This advanced configuration is meant to call artifact mirror (like JFrog Artifactory).
The yaml file from TENV_REMOTE_CONF path can have one part for each supported proxy : tofu, terraform, terragrunt and atmos.
yaml fields description
Each part can have the following string field : install_mode, list_mode, list_url, url, new_base_url, old_base_url, selector and part
With install_mode set to "direct", tenv skip the release information fetching and generate download url instead of reading them from API (overridden by _INSTALL_MODE env var).
With list_mode set to "html", tenv change the fetching of all releases information from API to parse the parent html page of artifact location, see selector and part (overridden by _LIST_MODE env var).
url allows to override the default remote url (overridden by flag or _REMOTE env var).
list_url allows to override the remote url only for the releases listing (overridden by _LIST_URL env var).
old_base_url and new_base_url are used as url rewrite rule (if an url start with the prefix, it will be changed to use the new base url).
If old_base_url and new_base_url are empty, tenv try to guess right behaviour based on previous fields.
selector is used to gather in a list all matching html node and part choose on which node part (attribute name or "#text" for inner text) a version will be extracted (selector default to "a" (html link) and part default to "href" (link target))
Example 1 : Retrieve Terraform binaries and list available releases from the mirror (TFENV_LIST_MODE is optional because TFENV_LIST_URL differ from its default(when TFENV_LIST_URL is not set, it copy TFENV_REMOTE)).
Example 3 : Retrieve OpenTofu binaries and list available releases from the mirror (TOFUENV_INSTALL_MODE and TOFUENV_LIST_MODE are optional because overloading TOFUENV_REMOTE already change them).
Example 4 : Retrieve OpenTofu binaries from the mirror and list available releases from the GitHub API (TOFUENV_INSTALL_MODE is optional because overloading TOFUENV_REMOTE already set it to "direct").
tenv uses lockfiles to ensure safe concurrent operations when multiple instances are run in parallel. This prevents race conditions during installation, uninstallation, and other operations that modify the local version cache.
Can be customized using the TENV_LOCK_PATH environment variable
Each tool (OpenTofu, Terraform, Terragrunt, Terramate, Atmos) uses its own lock file
Parallel execution behavior:
When multiple tenv instances attempt to run simultaneously:
The first instance creates its lock file successfully and proceeds with the operation
Subsequent instances fail to create the lock file (due to exclusive creation) and enter a retry loop
The retry mechanism waits 1 second between attempts and logs a warning message
Once the first instance completes and releases its lock, the next waiting instance can acquire the lock and proceed
Example retry behavior:
$ tenv tofu install 1.6.0 & tenv tofu install 1.6.1
[1] Installing OpenTofu 1.6.0
[2] can not write .lock file, will retry: file already exists
[2] can not write .lock file, will retry: file already exists
[1] Installation of OpenTofu 1.6.0 successful
[2] Installing OpenTofu 1.6.1
[2] Installation of OpenTofu 1.6.1 successful
Lock scope:
Operations that modify versions (install, uninstall) use locks to prevent conflicts
Read-only operations (list, list-remote, detect) don't need locks
Batch operations (InstallMultiple API) use a single lock for the entire batch
Locks are automatically cleaned up when operations finish (success or failure)
Interrupt signals (Ctrl+C) properly release locks to prevent deadlocks
Signature support
OpenTofu signature support
tenv checks the sha256 checksum and the signature of the checksum file with cosign (if present on your machine) or PGP (via gopenpgp). However, unstable OpenTofu versions are signed only with cosign (in this case, if cosign is not found tenv will display a warning).
Terraform signature support
tenv checks the sha256 checksum and the PGP signature of the checksum file (via gopenpgp, there is no cosign signature available).
Terragrunt signature support
tenv checks the sha256 checksum (there is no signature available).
Atmos signature support
tenv checks the sha256 checksum (there is no signature available).
Verifying tenv Signatures
You can use cosign to verify the signature of tenv releases. Below is an example installing the .rpm using dnf once we've verified the signatures/integrity.
> [!NOTE]
> The example below is a bash script that could be useful if you are wanting to automate installation of tenv in a developer environment. Adapt it to fit your specific use case.
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.