teriac CLI Auto-switch and pinning

Auto-switch and pinning

Let teriac pick the version each project needs from version files, the state file or required_version, switch on every cd with the shell hook, and pin versions for your team.

Auto-switch

auto-switch switches to the version your project needs, and installs it first if it isn't in the store.

teriac auto-switch
teriac as                               # alias
teriac as --provider tofu
teriac as -p tg

Where the version comes from

For Terraform and OpenTofu, teriac looks at these, in order, and uses the first it finds:

  1. A version file in the current folder
    • Terraform: .terraform-version, .tfswitchrc, .tfswitch.toml, or a terraform line in .tool-versions (asdf / mise)
    • OpenTofu: .opentofu-version, .tofu-version, an opentofu or tofu line in .tool-versions, then .terraform-version
  2. terraform.tfstate: the terraform_version field
  3. required_version in any .tf file. All constraint operators work: =, >=, >, <=, <, !=, ~>, and compound ones like ">= 1.3, < 2.0"

When a constraint allows several versions, teriac picks the newest stable release that fits.

For Terragrunt, see OpenTofu and Terragrunt.

Version files at a glance

File Read for Example
.terraform-version Terraform (and OpenTofu as a fallback) 1.9.0
.opentofu-version OpenTofu 1.8.0
.tofu-version OpenTofu 1.8.0
.terragrunt-version Terragrunt 1.2.1
.tgswitchrc Terragrunt 1.2.1
.tfswitchrc Terraform 1.9.0
.tfswitch.toml Terraform version = "1.9.0"
.tool-versions All three (asdf / mise) terraform 1.9.0
terragrunt.hcl, root.hcl Terraform and Terragrunt terraform_version_constraint = "~> 1.9"
*.tf Terraform and OpenTofu required_version = ">= 1.6"

A .tool-versions file can hold every tool at once:

terraform 1.9.0
opentofu 1.8.0
terragrunt 1.2.1

Switch on cd

The shell hook runs whenever you change directory (it uses your shell's own hooks, such as zsh's chpwd), so entering a Terraform project switches the version for you. Other folders cost one filesystem check and no subprocess.

A folder counts as a Terraform project if it has:

  • a version file (.terraform-version, .opentofu-version, .tofu-version, .tfswitchrc, .tfswitch.toml), or
  • a .tool-versions file with a terraform, opentofu or tofu line, or
  • a Terragrunt file (.terragrunt-version, .tgswitchrc, terragrunt.hcl, root.hcl), or
  • any *.tf files

It switches Terraform as above, and also switches OpenTofu when the project pins it with its own file (.opentofu-version, .tofu-version or .tool-versions), and Terragrunt when the project pins it.

cd ~/Downloads           # no .tf files → nothing happens
cd ~/projects/react-app  # no .tf files → nothing happens
cd ~/projects/infra      # has main.tf  → auto-switch runs silently
cd ~/projects/platform   # has .terraform-version → auto-switch runs silently

Set it up once

# Bash
printf '\neval "$(teriac shell-init bash)"\n' >> ~/.bashrc

# Zsh
printf '\neval "$(teriac shell-init zsh)"\n' >> ~/.zshrc

# Fish
printf '\nteriac shell-init fish | source\n' >> ~/.config/fish/config.fish

# PowerShell
Add-Content $PROFILE "`nInvoke-Expression (teriac shell-init powershell | Out-String)"

pwsh works as a name for PowerShell too. Open a new terminal afterwards.

To see what the hook does before you add it, print it: teriac shell-init zsh.

Tab completion

shell-init also adds tab completion:

  • teriac <tab> completes commands;
  • teriac use <tab> completes installed versions;
  • teriac --provider <tab> completes provider names.

Pin a version

pin writes a version file in the current folder, so teammates (and auto-switch, the shell hook, CI and teriac server) all use the same version. Each tool has its own file, so pinning one never switches another.

teriac pin                              # pin the active version → .terraform-version
teriac pin 1.9.0                        # pin a specific version
teriac pin --provider tofu              # → .opentofu-version
teriac pin --provider terragrunt        # → .terragrunt-version

Commit the file. teriac server plans each project with the exact version it pins, from these same files; see what gets planned.

A team workflow

# Once, by whoever upgrades the project
cd infra/
teriac install 1.9.^
teriac use 1.9
teriac pin
git add .terraform-version && git commit -m "Use Terraform 1.9"

# Everyone else, with the shell hook set up
git pull
cd infra/                # teriac installs and switches to the pinned version
terraform version