# Installing and Managing Terraform Versions

> Chapter 3 of the Courseiva HASHICORP-TERRAFORM curriculum — https://courseiva.com/learn/hashicorp-terraform/installing-and-managing-terraform

**Official objective:** 1.3 — Describe how to install and manage the Terraform CLI and its versions.

## Introduction

Exam objective 1.3 for the TF-003 exam focuses on installing and managing the Terraform CLI and its versions. This matters because if you install the wrong version of Terraform for your project, your code might fail or, worse, destroy infrastructure in an unpredictable way. Learning to control which version you use is like learning to pick the right key for a lock — a basic skill that prevents disasters.

## The Restaurant Kitchen Recipe Card Analogy

The Head Chef at a busy restaurant needs to manage recipe cards for every dish on the menu. Each dish, from a simple omelette to a complex soufflé, has its own specific recipe card. The head chef cannot just scribble a new recipe on a napkin every time a customer orders. They use a master binder of recipe cards, each versioned and dated. When a new menu is launched, the chef updates the binder with the correct recipe cards and archives the old ones. If a customer orders a dish from last year's special, the chef can pull the exact old card from the archive.

Now imagine a junior chef tries to use last year's recipe for a chocolate cake but the oven has been replaced with a different model. The temperature and timing instructions on the old card are wrong. The cake burns. This is exactly the problem that Terraform version management solves. Terraform providers and configurations change over time. A configuration written for one version might break with another. Professionals use version managers like tfenv or the built-in Terraform version constraints to ensure every team member uses the exact same Terraform version for a given project, just like the head chef ensures everyone uses the correct, current recipe card from the master binder.

## Core explanation

Terraform is a tool that lets you define and provision infrastructure using code. Infrastructure is the physical or virtual hardware that runs your applications: servers, databases, networking, and so on. The Terraform CLI (Command Line Interface) is the program you run on your computer to apply that code. Just like any software, Terraform gets new features and bug fixes over time, which means new versions are released.

Why does version management matter so much? Terraform configurations are written in a language called HCL (HashiCorp Configuration Language). As Terraform evolves, the way HCL works can change. A feature you used in version 0.12 might be deprecated (removed or no longer recommended) in version 1.5. If you run a configuration written for 0.12 with the 1.5 binary, you might get errors or unexpected behaviour. Version management ensures you always use the correct Terraform version for each project.

There are two main ways to manage Terraform versions. The first is to download a specific binary manually from the HashiCorp website and place it somewhere on your system. This works but can become messy if you work on multiple projects requiring different versions. The second, more professional approach, is to use a version manager tool. The most popular one is tfenv, which works on macOS and Linux. tfenv allows you to install, switch, and manage multiple versions of Terraform on the same machine. You can set a default version for your whole system and a project-specific version using a .terraform-version file. When you run 'terraform' commands, tfenv automatically picks the correct version based on that file.

Another key concept is the required_version setting inside your Terraform configuration file (usually named 'versions.tf'). This is a block of code that tells Terraform which versions of the CLI are allowed to run this configuration. For example:

terraform {
  required_version = ">= 1.0.0, < 2.0.0"
}

This constraint means the configuration can only be used with Terraform version 1.0.0 up to, but not including, 2.0.0. If a teammate tries to run it with version 0.15, Terraform will refuse and print an error message. This protects your infrastructure from being accidentally modified by an incompatible version.

Version management also applies to providers. A provider is a plugin that Terraform uses to interact with a cloud platform like AWS, Azure, or GCP. Each provider has its own versioning. You can set provider version constraints inside the same 'terraform' block, for example:

required_providers {
  aws = {
    source  = "hashicorp/aws"
    version = "~> 4.0"
  }
}

The tilde (~) with the greater-than sign means "allow any version in the 4.x range, but not 5.0 or higher". This ensures that you get minor updates and bug fixes without unexpectedly jumping to a breaking release.

The upgrade process also matters. When you want to move to a newer version of Terraform for a project, you typically run a command like 'terraform init -upgrade' to update the lock file that records which exact provider versions are being used. Then you run 'terraform plan' to check that no breaking changes have occurred. HashiCorp publishes upgrade guides for every major version bump, which detail specific changes you need to make to your code. Ignoring these guides is a common cause of production incidents.

Finally, Terraform stores a state file (terraform.tfstate) that maps your configuration to real-world infrastructure. The state file format can change between Terraform versions. If you upgrade Terraform without planning, you might end up with a state file that the new version cannot read, effectively locking you out of managing your own infrastructure. That is why version management is a critical skill for anyone using Terraform in a team or production environment.

## Real-world context

Sarah is a cloud engineer at a mid-sized software company that builds and deploys a web application on Amazon Web Services (AWS). The team has three microservices, each managed in a separate Git repository with its own Terraform configuration. Sarah started the project using Terraform version 0.12 two years ago. Last month, the team decided to upgrade one of the services to Terraform 1.5 to use a new data source that only exists in the newer version. The other two services will stay on 0.12 for now because their configurations are stable and the team does not want to risk breaking them in a busy release period.

Here is what Sarah does step-by-step:

- She installs tfenv on her laptop using Homebrew (a package manager for macOS). She runs 'tfenv install 0.12.31' and 'tfenv install 1.5.0' so both binaries are available.
- She navigates to the directory of the service that needs upgrading. She creates a file named '.terraform-version' containing exactly "1.5.0". Now whenever Sarah or any teammate runs a Terraform command in that directory, tfenv automatically uses Terraform 1.5.0.
- She also updates the 'required_version' in the 'versions.tf' file to ">= 1.5.0, < 2.0.0" to ensure that no one accidentally runs it with an older version if they do not have tfenv configured.
- She runs 'terraform init -upgrade' to download the latest provider plugins compatible with Terraform 1.5.
- She runs 'terraform plan' and sees that the plan shows 'no changes'. This is a good sign that the upgrade was safe, at least for the current state.
- She checks the HashiCorp upgrade guide from 0.12 to 1.5 and manually modifies a few deprecated attributes in the configuration, such as changing 'aws_instance' to use the newer 'aws_instance_v2' resource syntax. She runs 'terraform plan' again, and this time it shows the planned changes to update those resources.
- After code review, she applies the changes during a maintenance window. The infrastructure is updated successfully.

Sarah also sets a system-wide default version so new projects default to the latest stable Terraform. She runs 'tfenv use 1.5.0' to set the default globally. For the two services staying on 0.12, she simply creates a .terraform-version file with "0.12.31" in those directories. This setup allows her team to work on all three services without ever running the wrong command.

When a new developer joins, they only need to install tfenv and run 'tfenv install' (which reads the .terraform-version file) to get the correct binary. This saves hours of debugging and avoids accidental infrastructure destruction caused by version mismatches.

## Exam focus

The TF-003 exam tests objective 1.3 in several specific ways. You need to know the difference between the required_version setting and provider version constraints. The exam will likely present a scenario where a configuration has a required_version constraint, and you must identify what happens when a user runs it with an incompatible binary. The answer is always: Terraform will print an error and refuse to proceed. It will not attempt to run or partially apply the configuration.

Key concepts they love to test:

- The syntax for required_version: 'terraform { required_version = ">= 1.0.0" }'. You must know it goes inside the 'terraform' block, not the 'provider' block.
- Provider version constraints: They use the same 'required_providers' nested block inside 'terraform'. You must recognise the tilde operator '~>' which means "pessimistic version constraint". For example, '~> 2.0' means '>= 2.0, < 3.0'.
- Version managers: You should know that tfenv is a common tool, but the exam might ask about the general concept of version management. The correct answer is that it allows you to install and switch between multiple versions on the same system.
- The .terraform-version file: You need to know that it is a simple text file containing just the version number, and it is used by tools like tfenv to automatically select the correct version.
- The upgrade workflow: Questions may ask about the order of operations when upgrading. The correct sequence is: 1) Update required_version, 2) Run 'terraform init -upgrade', 3) Run 'terraform plan' to check for deprecations, 4) Apply changes if needed.

Common trap patterns:

- The exam might show a required_version that uses '>= 1.0, < 1.5' and ask if a user running 1.6 would succeed. The answer is no, because the constraint excludes 1.6.
- They might present a scenario where the user forgot to update the required_version after upgrading, and ask what will happen if they run 'terraform apply'. The answer is that Terraform will run successfully (since the binary is compatible), but team members with older versions might break later. The exam expects you to flag the missing constraint as a risk.
- They sometimes show provider version constraints that conflict. For example, one module requires 'aws >= 3.0' and another requires 'aws < 3.5'. You need to identify that the version range is the intersection: 3.0 to 3.4 inclusive.

Memorise these definitions exactly:

- Terraform CLI version: The version of the terraform binary.
- Provider version: The version of the plugin that interfaces with a specific cloud provider.
- Version constraint: A string like '>= 1.0.0' that specifies acceptable versions.
- Terraform Registry: Where providers and modules are published with version metadata.

Exam questions on this topic are usually straightforward if you have practised the commands and know the constraint syntax. Do not overthink them — the answer is often the simplest option that matches the rules described above.

## Step by step

1. **Check current Terraform version** — Run 'terraform --version' in your terminal to see what version is currently active. This tells you the starting point before any changes. It also shows installed provider versions.
2. **Set version constraint in configuration** — Add a 'required_version' line inside the 'terraform' block in your 'versions.tf' file. For example, 'terraform { required_version = ">= 1.0.0" }'. This documents the allowed versions and enforces them at runtime.
3. **Install the target version using a version manager** — Use tfenv (or similar) to install the specific Terraform version you need. Run 'tfenv install 1.5.0'. This downloads the binary and makes it available in your system. This step avoids downloading the wrong version from the web manually.
4. **Create a .terraform-version file** — In the root directory of your Terraform project, create a file named '.terraform-version' containing just the version number (e.g., "1.5.0"). This file is read by tfenv to automatically select the correct version when you navigate to that folder.
5. **Update provider versions with init -upgrade** — Run 'terraform init -upgrade' to update the .terraform.lock.hcl file with the latest provider versions that are compatible with your new Terraform version. This ensures your configuration uses up-to-date and compatible provider plugins.
6. **Run terraform plan to validate** — Run 'terraform plan' to see what changes Terraform would make. If the version upgrade introduced breaking changes, the plan will show modifications or errors. This is a safe way to test before applying.
7. **Apply changes in a controlled window** — If the plan shows expected changes (like updating deprecated resources), apply them during a maintenance window using 'terraform apply'. Always have a backup of your state file before applying, in case of unexpected issues.

## Comparisons

### required_version (CLI) vs provider version constraint

**required_version (CLI):**
- Controls which Terraform binary can run the configuration
- Set inside the terraform block using 'required_version'
- Uses simple comparison operators like >=, <, ~>, etc.

**provider version constraint:**
- Controls which version of a provider plugin is used
- Set inside the required_providers block within terraform
- Also uses comparison operators but applied to specific providers

### tfenv (version manager) vs Manual binary download

**tfenv (version manager):**
- Allows switching between versions per project
- Automatically selects version based on .terraform-version file
- Simplifies team collaboration by ensuring everyone uses the same version

**Manual binary download:**
- Downloading from releases page puts one binary in your PATH
- Requires manual effort to swap versions or maintain symlinks
- Can lead to version conflicts across projects on the same machine

### terraform init vs terraform init -upgrade

**terraform init:**
- Downloads provider plugins based on existing lock file
- Safe to run when no version changes have occurred
- Will not update to newer provider versions unless lock is missing

**terraform init -upgrade:**
- Updates the lock file to the latest acceptable provider versions
- Useful after upgrading Terraform CLI or changing constraints
- Should be followed by reviewing the plan for breaking changes

### Version constraint >= 1.0.0 vs Version constraint ~> 1.0

**Version constraint >= 1.0.0:**
- Allows any version from 1.0.0 upward (1.0, 1.1, 2.0, etc.)
- Broadest possible range, including major upgrades
- Risky for production because 2.0 may break configuration

**Version constraint ~> 1.0:**
- Allows any version from 1.0 to less than 2.0 (only patch and minor)
- More restrictive, prevents major version jumps
- Safer for production as it avoids breaking changes

## Diagram

_This diagram shows how tfenv uses per-project .terraform-version files to automatically select the correct Terraform version for different projects._

```mermaid
flowchart TD
    A[User has multiple projects] --> B[Project A uses Terraform 0.12]
    A --> C[Project B uses Terraform 1.5]
    B --> D[.terraform-version file with '0.12.31']
    C --> E[.terraform-version file with '1.5.0']
    D --> F[tfenv selects TF 0.12.31]
    E --> G[tfenv selects TF 1.5.0]
    F --> H[Runs terraform plan successfully]
    G --> I[Runs terraform plan successfully]
    H --> J[Infrastructure unchanged]
    I --> J
```

## Common misconceptions

- **Misconception:** You only need to worry about Terraform version management when you are upgrading to a completely new major version like from 0.12 to 1.0. **Reality:** Minor and patch version changes can also introduce breaking changes or behavioural differences, especially for providers. Always specify version constraints for both Terraform CLI and providers. (Beginners often assume that only major version bumps (like 1.0 to 2.0) matter, but in practice, provider versions frequently change even in minor releases.)
- **Misconception:** If you have multiple Terraform versions installed, you can just rename the terraform binary to switch between them. **Reality:** Renaming the binary is error-prone and unsupported. The correct approach is to use a version manager like tfenv or to create symlinks, but the most reliable method is to always use the exact binary path or a version file. (Beginners who come from a background of simply downloading software often try manual file management, not realising that Terraform expects a specific binary name and path to work correctly.)
- **Misconception:** Setting required_version in your configuration prevents anyone from running a wrong version on their local machine. **Reality:** Required_version is a safety check that prints an error, but it does not automatically switch versions. It only validates at runtime. The user must still have the correct version installed. (This distinction is subtle: people think the software will magically download the correct version, but it only checks what is already there.)
- **Misconception:** The .terraform-version file is a Terraform feature built into the CLI. **Reality:** The .terraform-version file is a convention used by third-party version managers like tfenv. Terraform itself does not read this file. It is not part of the official Terraform tooling. (The name and behaviour look similar to other tools like Node's .nvmrc, so beginners mistakenly believe Terraform natively supports it.)
- **Misconception:** Provider version constraints and Terraform CLI version constraints are interchangeable and can be used in the same block. **Reality:** They use different syntax and are placed inside the same 'terraform' block but under different keys. required_version controls the CLI binary, while required_providers controls provider plugins. (Both concepts involve version constraints, which leads to confusion about where each belongs and what each actually affects.)

## Key takeaways

- The required_version setting inside the terraform block tells Terraform which CLI versions are allowed to run your configuration, and Terraform will refuse to operate if the version does not match.
- Provider version constraints use the 'required_providers' block and the tilde operator (~>) to specify a range of acceptable versions, preventing unexpected upgrades.
- The .terraform-version file is read by tools like tfenv to automatically select the correct Terraform version for a project, but it is not a native Terraform feature.
- When upgrading Terraform, always run 'terraform init -upgrade' to update provider lock files, then run 'terraform plan' to detect any breaking changes before applying.
- Version management prevents state file corruption, which can occur if the state file format changes between Terraform versions.
- Always check HashiCorp's official upgrade guides when moving between major Terraform versions, as they detail specific code changes required.
- Multiple Terraform versions can coexist on the same machine using a version manager like tfenv, allowing work on projects with different requirements.
- A version constraint like '>= 1.0.0, < 2.0.0' means any version from 1.0.0 up to but not including 2.0.0 is acceptable.

## FAQ

**How do I install a specific old version of Terraform?**

Use a version manager like tfenv (on macOS/Linux) or tfswitch (also cross-platform). Run 'tfenv install 1.0.1' to download and make that version available. Alternatively, download the exact binary from the HashiCorp releases page on GitHub.

**What happens if I run a configuration with a different Terraform version than it was written for?**

If the configuration includes a required_version constraint, Terraform will refuse to run and show an error message stating the version mismatch. If there is no constraint, it will attempt to run, which may cause failures or unexpected behaviour due to deprecated features.

**Is the .terraform-version file the same as a version constraint in the code?**

No. The .terraform-version file is a convention used by tools like tfenv to select the right binary. The version constraint in the code (required_version) is a Terraform feature that validates which binary can run the configuration. They work together but are separate.

**Can I have multiple versions of Terraform installed at the same time?**

Yes. Version managers like tfenv allow you to install multiple versions side by side. You can switch between them globally or per-project using the .terraform-version file. This is common when you work on different projects that require different Terraform versions.

**Do I need to update required_version every time I upgrade Terraform?**

Yes. After upgrading the binary you use, update the required_version in your configuration to match the new range. This ensures that everyone on the team uses the same version and that CI/CD pipelines enforce consistency.

**Why does my terraform plan show changes after I only upgraded the Terraform version?**

Upgrading Terraform may change how it interprets your configuration. Deprecated attributes or resources can be replaced with new ones. Also, the new version may reorder or rename resources in the state file. Always review the plan carefully before applying.

## Check your understanding

1. **What does the 'required_version' setting in a Terraform configuration do?**

   Answer: It defines which versions of the Terraform CLI are allowed to run the configuration. If the running version does not match, Terraform prints an error and stops.

2. **Which file is used by version managers like tfenv to automatically select the correct Terraform version for a project?**

   Answer: The '.terraform-version' file, which contains a single line with the version number (e.g., '1.5.0').

3. **What does the tilde operator (~>) in a provider version constraint, for example '~> 3.0', mean?**

   Answer: It means '>= 3.0, < 4.0', allowing any version in the 3.x range but preventing a jump to 4.0 or higher.

4. **A team runs a Terraform configuration with required_version = ">= 1.0.0" but the user has Terraform 0.15 installed. What will happen?**

   Answer: Terraform will refuse to run and display an error because 0.15 is below the minimum specified version of 1.0.0.

5. **What is the purpose of running 'terraform init -upgrade' when upgrading Terraform?**

   Answer: It updates the provider lock file to the latest compatible provider versions for the new Terraform version, ensuring you use up-to-date plugins.

---

Interactive version with quiz and diagrams: https://courseiva.com/learn/hashicorp-terraform/installing-and-managing-terraform
