What Changed and Migration

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production; see the section bibliography for the reference material consulted while preparing these pages.

Infrastructure code outlives the tutorials it was copied from. A configuration written from a book published in 2024 or early 2025 still mostly works, but the tool around it has moved on: the language gained ephemeral values and actions, the S3 backend stopped needing a lock table, the providers shipped new major versions, Terraform Cloud changed its name, a whole alternative interface was archived and the free security scanner was folded into another product. This page collects those changes in one place, with the version or date at which each happened, and says what to do about each.

The baseline is Terraform 1.17 (1.17.0 was released on 2026-10-21) and OpenTofu 1.13 (1.13.0 was released on 2026-09-30). The two books the section draws on were written against Terraform about 1.9 and OpenTofu about 1.8 (Hafner, 2025, with hashicorp/aws at ~> 5.0) and against Terraform 1.4 to 1.8 with hashicorp/google pinned to exactly 5.38.0 (Wang, 2024); both eras therefore end just before the 1.10 release of 2024-11-27. Every date below was checked on the official release pages, changelogs or registry on 2026-10-24, and what could not be confirmed is worded cautiously. The page is the last stop of the reading path: each row links to the page of this section that explains the topic in depth, for example State, Backends and Remote State and OpenTofu.

Book era to current

The table summarises the points where a configuration, command or habit taught by the books has a different current answer. The detail, including the examples, is on the page named in the last column.

In the books (2024 to early 2025 era) Current approach Where

The S3 backend needs a DynamoDB table for state locking (Hafner)

use_lockfile = true, native S3 locking: added in 1.10, generally available in 1.11. The DynamoDB arguments are deprecated.

Backends and Remote State

"Terraform Cloud"

HCP Terraform, renamed on 2024-04-22. The legacy Free plan ended on 2026-03-31.

HCP Terraform and Enterprise

CDK for Terraform as an alternative interface (Hafner, chapter 11)

Archived on 2025-12-10; migrate with cdktf synth --hcl.

Machine-Readable Output and Integrations

terraform refresh and terraform taint

plan or apply with -refresh-only, and -replace=ADDRESS. Since 1.17 there is also -minimal-refresh.

CLI Essentials

-state and -state-out flags

Deprecated since 1.10: set the path of the local backend.

State

The template_file data source of the template provider

The templatefile() and templatestring() functions.

Functions

tfsec as a separate scanner

tfsec’s scanning engine is part of Trivy; tfsec stays available but is no longer where development happens.

Code Quality and Security Scanning

Secrets passed as plain arguments that end up in state

Ephemeral resources, variables and outputs (1.10) and write-only arguments (1.11).

Sensitive Data, Ephemeral and Write-Only

hashicorp/aws at ~> 5.0; hashicorp/google pinned to exactly 5.38.0

Current majors with ~> constraints and the dependency lock file; see the provider table below.

Providers

No required_version, mixed CLI versions between machines

Always declare required_version and pin the CLI version in CI.

CI/CD and Automation

Old action majors such as actions/checkout@v2 or v3 and hashicorp/setup-terraform@v1 or v2

actions/checkout@v7 and hashicorp/setup-terraform@v4; see the actions section below.

CI/CD and Automation

Test mocks are beta

Mocks are generally available since 1.7; mock_provider supports ephemeral resources in 1.17.

Testing

terraform env

Deprecated alias of terraform workspace.

Workspaces, Environments and Project Structure

Static CI secrets in TF_VAR_ variables; a service account with roles/editor and a downloaded JSON key (Wang)

OIDC and Workload Identity Federation from CI, HCP Terraform dynamic provider credentials, least-privilege roles.

CI/CD and Automation

A Jenkins job that archives terraform.tfstate as a build artifact (Wang)

Never: state holds secrets. Use a remote backend with encryption and locking.

Backends and Remote State

An output block with a condition argument (Wang, an error)

A precondition block inside the output, or a check block.

Variables, Outputs and Locals

A tf.tfvars file "loaded automatically" (Wang, an error)

Only terraform.tfvars, terraform.tfvars.json and *.auto.tfvars / *.auto.tfvars.json are loaded automatically.

Variables, Outputs and Locals

A gcs backend with key and region (Wang, an error)

The gcs backend uses bucket and prefix; key and region are S3 arguments.

Backends and Remote State

"No built-in mechanism for module dependencies" (Wang, an error)

depends_on on module blocks, available since Terraform 0.13.

Meta-Arguments: count, for_each and depends_on

export TF_VAR_name shown for Windows (Wang)

PowerShell: $Env:TF_VAR_name = "value".

Variables, Outputs and Locals

state pull and state push to move local state to a remote backend (Wang)

Change the backend block and run terraform init -migrate-state.

Backends and Remote State

Retired Google Cloud images, versions and resources: debian-10, MySQL 5.7, google_cloudfunctions_function (1st gen), google_cloud_run_service, gcr.io (Wang)

Current image families, google_cloudfunctions2_function, google_cloud_run_v2_service and Artifact Registry.

Terraform on Google Cloud

aws_s3_bucket with an acl argument; a nonexistent aws_rds_instance resource (Wang)

aws_s3_bucket_acl or, usually, ownership controls with ACLs disabled; aws_db_instance for RDS.

Terraform on AWS

kubernetes_ingress and kubernetes_service without _v1, the kubernetes.io/ingress.class annotation; a kubernetes_role bound by a ClusterRoleBinding; GKE master authorized networks open to 0.0.0.0/0 (Wang)

The kubernetes_*_v1 resources with ingress_class_name; a matching Role and RoleBinding; restricted authorized networks.

Docker, Kubernetes and Helm Providers

timestamp() in a resource name or tag (Wang): a perpetual diff

plantimestamp(), the time_static resource, or lifecycle.ignore_changes.

Functions

Invented Checkov check IDs and TFLint output; checkov -d <file> (Wang)

Real output from current tool versions; checkov -f for a single file and -d for a directory.

Code Quality and Security Scanning

The terraform env deprecation and the template_file replacement predate 1.10, so the changelogs above do not mention them. The terraform env command page states that the command is deprecated and that terraform workspace should be used instead. The hashicorp/template provider that supplied template_file was archived on 2020-10-08 and is read-only; the built-in templatefile() and templatestring() functions replace it.

Terraform 1.10 to 1.17

The table lists, per minor release, the release date and the changes that matter when migrating. Dates are the publication dates of the .0 releases on GitHub; the entries come from the changelog of each minor line. A line of the changelog is paraphrased, not quoted.

Version Released Changes to know about

1.10

2024-11-27

Ephemeral resources, ephemeral input variables and outputs, and the ephemeralasnull function. The S3 backend gains native state locking; when combined with DynamoDB, locks are taken from both. The deprecated S3 arguments for assuming a role were removed, so use the assume_role block. The -state flag of plan, apply and refresh is deprecated. moved blocks respect reserved keywords, so a resource type named like a top-level block needs the resource. prefix.

1.11

2025-02-27

Write-only attributes. S3 native locking (use_lockfile) is generally available and the DynamoDB arguments are deprecated. The -junit-xml option of terraform test is generally available, and run blocks gain state_key. The azure backend authentication was aligned with the AzureRM provider.

1.12

2025-05-14

An OCI Object Storage backend. import blocks can import by identity, which excludes id. Linux kernel 3.2 or later is required.

1.13

2025-08-20

The terraform stacks command. In terraform test, external variables referenced in test files should have a variable block in the test file.

1.14

2025-11-19

List resources in *.tfquery.hcl files and the terraform query command. A top-level action block. validate -query validates query files offline. Parallelism inside container runtimes can drop with a CPU bandwidth limit.

1.15

2026-04-29

The deprecated attribute on variable and output blocks. validate checks the backend block. The S3 backend supports authentication through aws login. In the S3 backend, AWS_USE_FIPS_ENDPOINT and AWS_USE_DUALSTACK_ENDPOINT accept only true or false. Better detection of deprecated attributes and blocks.

1.16

2026-08-26

import blocks inside modules. The store block of terraform_data. Action triggers get on_failure (halt, taint or continue) and actions get before_destroy and after_destroy. state show -json. bastion_host_key is now correctly applied by provisioners, so review the configured key before upgrading.

1.17

2026-10-21

Variables and locals in provider requirements. The -minimal-refresh planning option. Terraform Policy is announced as generally available in the changelog (see below). mock_provider supports ephemeral resources. terraform version -json gains a format_version field. log and pow raise errors on infinite results.

On 2026-10-24 the latest patch releases listed in the changelogs were 1.17.0 and 1.16.7 (published 2026-10-22). Patch releases of the older lines still receive fixes, as the 1.15.9 and 1.16.x entries show, but the changelogs are the place to look rather than this page. The upgrade guides for each line are the official companion to the changelog; they are referenced at the end of the page.

Deprecations and removals at a glance

What Version Replacement

S3 backend DynamoDB locking arguments

Deprecated in 1.11

use_lockfile = true; both mechanisms can run together while migrating.

S3 backend arguments for assuming a role outside assume_role

Removed in 1.10

The assume_role block.

-state flag of plan, apply and refresh

Deprecated in 1.10

The path argument of the local backend.

terraform refresh, terraform taint

Superseded; see the CLI page for the precise status

-refresh-only and -replace=ADDRESS.

Experimental -policies build requirement

Lifted in 1.17

-policies no longer needs an experimental build or -allow-experimental-features.

Migrating S3 locking from DynamoDB to use_lockfile

The Bookshelf state lives in an S3 bucket. A book-era backend declares a DynamoDB table; the current one uses a lock file next to the state object. The migration is done in two steps so that both lock sources protect the state during the transition.

terraform {
  required_version = ">= 1.11"

  backend "s3" {
    bucket       = "bookshelf-tfstate-example"
    key          = "prod/network/terraform.tfstate"
    region       = "eu-west-1"
    encrypt      = true
    use_lockfile = true

    # Step 1: keep the old table while every pipeline moves to the new CLI.
    # dynamodb_table = "bookshelf-tf-locks"
  }
}

Run terraform init -reconfigure after changing the backend block; the state itself does not move. Once every runner uses a version that supports use_lockfile, remove the dynamodb_table argument and, later, the table. The changelog states that while both are configured locks are taken from both sources. Native locking needs conditional writes on the bucket; whether an S3-compatible store such as a local emulator supports them is not documented in the pages consulted, so test before relying on it. OpenTofu added native S3 locking in its 1.10 line; see OpenTofu.

Provider major versions

A provider major release is independent of the Terraform version. The table gives the release date of each major according to the Terraform Registry, the most recent version observed on 2026-10-23 and 2026-10-24, and the point the books are behind.

Provider Majors and dates Current (observed) Book-era pin and what to do

hashicorp/aws

5.0.0 on 2023-05-25; 6.0.0 on 2025-06-18

6.70.0 (2026-10-22)

Hafner uses ~> 5.0. Move to ~> 6.0 after reading the version 6 upgrade guide. Version 6 adds a region argument to most resources (enhanced region support), removes the endpoints.opsworks, endpoints.simpledb and endpoints.worklink provider arguments, and in the aws_s3_bucket data source bucket_region replaces region.

hashicorp/google

6.0.0 on 2024-08-26; 7.0.0 on 2025-08-26; 8.0.0 on 2026-08-26

8.8.x (8.8.1 published 2026-10-23)

Wang pins exactly 5.38.0. Moving to 8.x crosses three majors, so upgrade one major at a time and clear deprecation warnings first. The 7.0.0 guide adds import-format validation and deletion_protection for AlloyDB clusters, among other changes; 8.0.0 removes resources such as the BeyondCorp app connection and connector, IAP brand and client, and the Notebooks resources (use google_workbench_instance).

hashicorp/azurerm

4.0.0 on 2024-08-22; 5.0.0 on 2026-07-28 (changelog dated 2026-07-27)

5.11.0 (2026-10-23)

The current major is 5.x; 4.x is the previous one, and material that says "AzureRM v4" is outdated. The 5.0 guide, for example, makes rbac_authorization_enabled required on azurerm_key_vault and gives azurerm_storage_container a storage_account_id argument.

kreuzwerker/docker

3.0.0 on 2023-01-13; 4.0.0 on 2026-04-03

4.6.0

A constraint ~> 3.0 still resolves to the 3.x line and will never install 4.x. Check each release note before moving to 4.x.

hashicorp/kubernetes

2.0.0 on 2021-01-21; 3.0.0 on 2025-12-04

3.4.0

Use the _v1 resource names; the unversioned kubernetes_ingress and kubernetes_service that Wang uses are not the current ones.

hashicorp/helm

2.0.0 on 2020-12-19; 3.0.0 on 2025-06-18

3.3.0

Version 3 is a new major; read its upgrade notes (not summarised here) before changing the constraint.

The safe upgrade procedure is the same for every provider. First upgrade to the last release of the previous major and run a plan with no unexpected changes and no deprecation warnings; then raise the constraint, run terraform init -upgrade, and review the plan before applying. The dependency lock file records the chosen version, so commit the resulting .terraform.lock.hcl change on its own.

terraform {
  required_version = ">= 1.17"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
    google = {
      source  = "hashicorp/google"
      version = "~> 8.0"
    }
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 5.0"
    }
    docker = {
      source  = "kreuzwerker/docker"
      version = "~> 4.0"
    }
  }
}

Terraform Cloud becomes HCP Terraform

Both books say "Terraform Cloud". HashiCorp renamed it HCP Terraform on 2024-04-22. The CLI block that connects to it is still called cloud, the environment variables keep their TF_CLOUD_ prefix, and the provider is still hashicorp/tfe (0.82.0 on 2026-10-23). What did change is commercial: the legacy member-based Free plan ended on 2026-03-31, and organizations moved to the enhanced Free tier, which allows up to 500 managed resources at no charge and is billed per managed resource beyond that. Hafner’s chapter 8 pricing and limits are therefore outdated. Terraform Enterprise moved to semantic versions: the monthly scheme ended at v202507-1, and the 2.0.x line is the newest, with 2.0.8 (2026-09-23) as its latest patch release.

CDK for Terraform

The README of the hashicorp/terraform-cdk repository announced that CDKTF would sunset and be archived on 2025-12-10, after which HashiCorp would no longer maintain or develop it. The repository is archived on GitHub today (last push 2025-12-10). The precise wording is therefore "sunset and archived", not merely "deprecated": the code stays available read-only under the MPL, with no further fixes or compatibility updates, and the README suggests community forks. The documented migration path is to generate HCL from the project:

cdktf synth --hcl
terraform init
terraform plan

The generated files need review and tidying before they are good HCL. For programmatic access to Terraform, the supported route is the JSON output and the machine-readable UI described in Machine-Readable Output and Integrations.

tfsec to Trivy

The README of aquasecurity/tfsec announces a migration to Trivy: Trivy natively supports Terraform scanning with the engine tfsec laid the foundations for, and the project encourages tfsec users to move. It also says tfsec "will continue to remain available for the time being" while engineering attention goes to Trivy; the repository is not archived as of 2026-10-24. In a pipeline, replace the tfsec step by trivy config, and review severity filters and ignore comments, because the rule identifiers and ignore syntax are not guaranteed to be identical. See Code Quality and Security Scanning.

Terraform Policy maturity

Terraform Policy is a case where two official sources differ, and both statements are accurate as of 2026-10-24. The 1.17.0 changelog (2026-10-21) says Terraform Policy is now generally available and that the -policies flag for plan, apply and query no longer requires an experimental build or the -allow-experimental-features flag. The documentation pages of the policy reference still carried a beta label and the usual warning against using beta features in production when the section was written. Until the documentation catches up, treat the CLI behaviour as generally available, the documentation as the more cautious statement, and verify the status on the policy documentation before making it a gate in production. See Policy as Code.

GitHub Actions majors

The CI examples of this section use actions/checkout@v7 and hashicorp/setup-terraform@v4, and opentofu/setup-opentofu@v2. These are the majors shown in the READMEs of those repositories on 2026-10-24 (latest releases: checkout v7.0.1 on 2026-07-20, setup-terraform v4.0.1 on 2026-05-12, setup-opentofu v2.0.2 on 2026-06-29). Some tutorials still use setup-terraform@v3 and older checkout majors; those still run, but the maintained majors are newer. Pin a major (or a full commit hash) and let Dependabot propose bumps.

steps:
  - uses: actions/checkout@v7
  - uses: hashicorp/setup-terraform@v4
    with:
      terraform_version: "1.17.0"
  - run: terraform fmt -check -recursive
  - run: terraform init -input=false
  - run: terraform validate

Licensing timeline

Date Event

2023-08-10

HashiCorp announces the move from MPL-2.0 to the Business Source License 1.1 for its products, including Terraform.

2023-09-07

Terraform 1.5.7, the last MPL-2.0 release of the 1.5 series, is published.

2023-09 (day not confirmed)

The OpenTofu project is accepted by the Linux Foundation; secondary sources give 2023-09-20, which the project’s own pages do not repeat.

2023-10-04

Terraform 1.6.0, the first release under the BSL, is published.

2024-01-10

OpenTofu 1.6.0, the first stable release, under MPL-2.0.

2025-02-27

IBM completes its acquisition of HashiCorp.

2025-04-23

OpenTofu is accepted as a CNCF Sandbox project.

The BSL announcement date, the CNCF acceptance date and the OpenTofu 1.6.0 date are carried over from the sibling page OpenTofu, which cites the primary sources; the release dates of 1.5.7 and 1.6.0 come from the releases page.

Migration checklist

For a Bookshelf repository written from a book of this era, work through the changes in this order, one commit each:

  • Pin the CLI with required_version and move CI to the current action majors.

  • Run terraform init -upgrade on the newest 1.x minor you can adopt, reading the upgrade note of each minor from 1.10.

  • Replace -state and -state-out by the path of the local backend, and refresh and taint by -refresh-only and -replace.

  • Switch the S3 backend to use_lockfile, keep the DynamoDB table for one release cycle, then drop it.

  • Upgrade providers one major at a time, starting with the last release of the current major, and review the lock file.

  • Move secrets out of state with ephemeral values and write-only arguments where the provider offers them.

  • Replace template_file with templatefile(), and tfsec with Trivy.

  • Update references to Terraform Cloud and re-check plan limits against the HCP Terraform pricing page.

  • Decide whether OpenTofu is an alternative for your team; the migration notes are on the OpenTofu page.

Reading order after this page: Best Practices and Troubleshooting.