Terraform 1.17 explained: provider variables, minimal refresh and Policy GA
Terraform 1.17.0 is out. Variables work in required_providers, -minimal-refresh speeds up big plans at the cost of some drift detection, and Terraform Policy runs in the normal CLI. What changed from 1.16, and how we'd upgrade.
part 3 of 3 · Platform releases, explained from scratchthe idea1.17 adds provider variables, a lighter plan and GA policy checks.
after reading, you can- Tell your team which Terraform 1.17 changes affect them and which don't
- Spot when -minimal-refresh is safe and when it'll hide drift you need to see
- Set up an upgrade to 1.17 that checks pins, parsers and certificate paths first
Terraform 1.17.0 came out on October 21, 2026. Read on if you run large states (there's a new -minimal-refresh option with a catch), keep providers in more than one private registry (required_providers now takes constant variables and locals), or write policy (Terraform Policy no longer needs an experimental build). Otherwise it's a quiet 1.x minor eight weeks after 1.16.0.
- You describe infrastructure in HCL, HashiCorp's configuration language.
- Providers are plugins that call each API: AWS, Azure, Snowflake, Okta.
- A state file records what Terraform already manages.
- terraform plan previews a change, and terraform apply makes it.
- IBM owns HashiCorp (Feb 2025); Terraform is under the BSL (Aug 2023).
What changed in 1.17
Not much to read this time: three new features, three enhancements, seven bug fixes and two notes. Tags are HashiCorp's, except the notes, which we marked changed.
Terraform 1.17.0 at a glance
You can now take the source and version in required_providers from constant input variables and locals. Same rules as 1.15's dynamic module sources: nothing may depend on plan results.
Refreshes only the resource instances Terraform plans to change, so plans on big states make fewer API calls. Drift on unchanged resources goes unseen.
The -policies flag for plan, apply and query no longer needs an experimental build or -allow-experimental-features. Query policies check resources that list blocks discover.
Log lines from terraform init now name the provider versions. Handy when you're working out why an install failed.
terraform test's mock_provider can now fake ephemeral resources, so a test of a module that uses them can run on mocks.
Terraform used to drop warnings and errors from ephemeral resource renewals. It shows them now, so a few new warnings may turn up.
No more panics from log and pow when the result isn't a number. They also error out now on plus or minus infinity, which nothing downstream could use anyway.
There's a format_version field in terraform version -json now. If your tooling ignores unknown fields you're fine, but watch the field in later releases.
Provider requirements can now use variables, within limits. This builds on 1.15 (April 29, 2026), where module source and version started reading variables marked const = true and locals built from them. Now required_providers can too. Don't be thrown by HashiCorp's reference page for the terraform block, which still says it won't take input variables. The pull request's example uses an organization variable inside a private registry address and keeps the version in a local. Set the values with -var, a var file or environment variables.
This is useful if one codebase runs against more than one private registry or organization. Until now, teams in that position kept near-identical copies of the terraform block, or rewrote it with scripts before init. One limit doesn't move. The value has to be known before planning starts, so it can't come from a resource or a data source. Terraform 1.15 rejects that case at init for module sources with an "Invalid module source" error, and provider sources follow the same constraints.
A faster plan for big states, if you accept the trade-off. Normally a plan refreshes every resource it manages before doing anything else, which costs at least one read call each. On a state with thousands of resources, that's the slow part, and it's also when providers start rate limiting. Issue 35290 asked for a fix back in 2024, from someone who found -refresh=false too risky. -minimal-refresh has Terraform compare configuration with the prior state first. Instances with no planned change skip the refreshdefinitionBefore planning, Terraform asks each API what really exists and updates state to match. That's the refresh, and on big states it's the slow part., and the ones with changes are refreshed and planned again. Each one decides for itself, so refreshing one resource doesn't pull in the ones that depend on it.
The documentation is frank about the cost. Like -refresh=false, it ignores changes made outside Terraform to anything you didn't touch, so the plan can be incomplete or wrong. You can't combine it with refresh-only mode or with -refresh=false. HashiCorp also says to avoid it when you upgrade provider versions, so Terraform can write schema changes into state. We'd use it for fast feedback on pull requests and keep a full-refresh plan in front of every production apply.
Terraform Policy is out of experimental status in the CLI. For anyone who hasn't tried it, it's HashiCorp's HCL-based policy as code: .policy.hcl files with provider, resource and module blocks. HCP Terraform can evaluate them at setup time, before providers or modules download, at plan time and after apply, when IDs and ARNs exist. Enforcement is Advisory, Mandatory_overridable or Mandatory. Sentinel and Open Policy Agent haven't gone away.
From 1.17, -policies works on plan, apply and query in a normal build. Query policies check what your list blocks find and report as text or JSON. Before you call it production-ready, though, look at the docs too. HashiCorp's Terraform PolicydefinitionHashiCorp's HCL-based policy as code, kept in .policy.hcl files. docs (v0.5.x) still said "this functionality is in beta" when we checked on October 22, 2026. Easy to miss: the pull request the GA entry links to changes how policies see a replacement. It now arrives as a separate create and delete, each with its own attribute values. It used to be one update.
Smaller changes that can still show up in your pipeline. Two fixes could change output you're used to. Diagnostics from renewing ephemeral resources now appear, and HashiCorp doesn't expect that to break anything. log and pow now fail instead of returning infinity. If a wrapper parses terraform version -json, check that it tolerates the new format_version field. And if anything in your build trusts certificates through the compromised eMudhra intermediates, the Go 1.26.10 change in 1.17.0 and 1.16.7 will make those connections fail.
Version against version
A quick sense of pace: a minor release every few months, a patch to the current one most weeks. Here's 1.17 next to the two before it, headline items only. The changelogs have everything else.
| Item | 1.15 | 1.16 | 1.17 |
|---|---|---|---|
| Released | April 29, 2026 | August 26, 2026 | October 21, 2026 |
| Latest patch (Oct 22, 2026) | 1.15.9 (August 19, 2026) | 1.16.7 (October 22, 2026) | 1.17.0 |
| Dynamic sources from const values | Module source and version from const variables and locals | No change in the changelog | Provider source and version from const variables and locals |
| Import | No headline change | import blocks work inside modules | No headline change |
| Refresh and planning | No headline change | No headline change | -minimal-refresh option |
| Policy | No mention in the changelog | HCP Terraform policy summaries in the CLI; plugin credentials from the backend | Terraform Policy GA for -policies on plan, apply and query |
| Lifecycle and actions | No headline change | lifecycle destroy = false; on_failure modes halt, taint, continue | No headline change |
| Platforms, output and syntax | Windows ARM64 builds; deprecated attribute on variables and outputs | Linux s390x builds; graph -format=mermaid; state show -json | format_version in version JSON |
| Upgrade notes | S3 backend FIPS and dual-stack env vars accept only true or false | Provisioners now apply bastion_host_key; check it | None listed; upgrade guide cites the 1.x promises |
How long will 1.16 be supported? Nobody has published a date we can point you to. What we can see is that 1.16 is still getting patches: 1.16.7 arrived the day after 1.17.0. The support-period article now redirects to IBM's support portal, which didn't load for us without a sign-in, and the public 1.x compatibility promise only says the series gets at least 18 months of maintenance after 1.0. If you need a date for an audit or a contract, ask HashiCorp support.
Terraform releases and advisories, November 2025 to October 2026
- Nov 19, 2025Terraform 1.14.0
List resources, the terraform query command and the actions block arrive.
- Apr 29, 2026Terraform 1.15.0
Const variables in module sources, Windows ARM64 builds, the convert function.
- Jul 6, 2026HCSEC-2026-17 (Terraform Enterprise)
Module publishers could pull arbitrary files through VCS ingestion. Patch to 2.0.4 or 1.2.4.
- Jul 28, 2026HCSEC-2026-23 (terraform-mcp-server)
Three CVEs in the HTTP transport. Fixed in 1.1.0.
- Aug 26, 2026Terraform 1.16.0
import in modules, terraform_data store block, destroy = false.
- Sep 9, 20261.17.0-beta1
- Oct 7, 20261.17.0-rc1
rc2 followed on October 14.
- Oct 21, 2026Terraform 1.17.0
Provider requirement variables, -minimal-refresh, Terraform Policy GA.
- Oct 22, 2026Terraform 1.16.7
Go 1.26.10 for 1.16 users who aren't moving yet.
And two advisories from this summer. Neither is in the Terraform CLI. If you run self-managed Terraform Enterprise, read HCSEC-2026-17: a user who can publish a registry module from a VCS repository could pull files from outside it into the module and download them. It hits v202506-1, v202507-1 and 1.0.0 through 2.0.3, with fixes in 2.0.4 and 1.2.4. If you run terraform-mcp-server, HashiCorp's MCP server for AI tools, read HCSEC-2026-23. Versions 0.2.1 through 1.0.0 had three HTTP transport flaws, one of which could send the server's bearer token to an attacker's endpoint. 1.1.0 fixes them; stdio-only setups were safe.
Architecture and the upgrade
Nothing about Terraform's overall shape changes in 1.17: configuration, the CLI or a remote runner, providers, state, and the APIs at the end. A few decisions move. Init can work out a provider's address from variables, a plan can skip refreshing what you didn't touch, and you don't need an experimental build to run policy from the Terraform CLI. We've used HashiCorp's own component names in the diagrams and simplified the rest.
Before: a Terraform 1.16 run
Under 1.16 you hard-code the provider address, every plan refreshes every managed resource, and -policies only works in an experimental build.
Read the diagram as text
- required_providers → terraform init: provider address
- Root module and modules → terraform init: module sources
- terraform init → terraform plan
- terraform plan → State file: read prior state
- terraform plan → Provider APIs: refresh all
- -policies flag → terraform plan: opt-in, experimental
After: a Terraform 1.17 run
In 1.17 provider addresses can come from const variables and locals, -minimal-refresh limits refresh to changed resources, and -policies works in a normal build.
Read the diagram as text
- Const variables and locals → required_providers: known before plan
- required_providers → terraform init: provider address
- terraform init → terraform plan
- .policy.hcl files → terraform plan: -policies (GA)
- .policy.hcl files → terraform query: query policies
- terraform plan → State file: read prior state
- terraform plan → Provider APIs: refresh changed only
- Provider source and version are hard-coded strings in each terraform block
- Every plan refreshes every managed resource, or you turn refresh off entirely
- Running -policies locally means an experimental build and an extra flag
- A replaced resource reaches policy as a single update
- terraform version -json has no format_version field
- Provider source and version can come from const variables and locals
- -minimal-refresh refreshes only the instances you're changing
- -policies works on plan, apply and query in a normal build
- A replaced resource is evaluated as a separate create and delete
- terraform version -json includes format_version
Don't expect much from the upgrade guide. For 1.17 it says the release honors the v1.0 compatibility promises and points you at the changelog. That's normal inside 1.x. If something breaks, look at providers first, then at scripts that parse CLI output, then at the edge cases in the bug fixes. This is the order we'd go in.
Upgrading from 1.16 (or earlier) to 1.17
- 01Inventory versions and pins
List the Terraform version every pipeline, runner and laptop uses, and every required_version constraint. A constraint like ~> 1.16.0 blocks 1.17 until you change it. If you're on 1.15 or earlier, read the upgrade notes in the 1.16 and 1.15 changelogs too: bastion_host_key for provisioners, and the S3 backend's FIPS and dual-stack variables.
- 02Check what parses Terraform's output
Track down anything that reads terraform version -json and make sure it ignores unknown fields or reads format_version. HashiCorp's advice is to use current hashicorp/terraform-json and terraform-exec.
- 03Check certificate paths
Go 1.26.10, used for 1.17.0 and 1.16.7, no longer trusts certificates from the compromised eMudhra intermediates. If a private registry, proxy or backend chains through one, it'll break, so check before rollout.
- 04Run plans side by side in a lower environment
Run plans with 1.16 and 1.17 against the same state with the same provider versions, with full refresh. Expect identical plans. Watch for new warnings from ephemeral resource renewals and errors from log or pow.
- 05Upgrade providers separately
Don't change Terraform and provider versions in the same step. During provider upgrades, plan without -minimal-refresh or -refresh=false so schema changes reach state.
- 06Adopt the new features on purpose
Move duplicated terraform blocks to const variables where it helps. Try -minimal-refresh on pull-request plans. Pilot Terraform Policy beside your Sentinel or OPA rules before you rely on it.
- 07Cut over and record it
Raise required_version, rebuild runner images and set the new version on your HCP Terraform or Terraform Enterprise workspaces. Production applies still get a full-refresh plan first.
Who gains from 1.17
Most of what's in 1.17 helps platform teams that run Terraform for other teams. If you write a few modules for one account, you can take this release at your own pace.
- Platform teams with one codebase and several private registries or organizations: set the provider source per environment and stop copying terraform blocks or patching them with scripts.
- Teams whose large states run into provider rate limits get a supported halfway house between a full refresh and -refresh=false when they just want a quick plan.
- If you write guardrails, you can run HCL policies from the Terraform CLI in CI now. Policies see a replacement as a create and a delete.
- Anyone wrapping the CLI in scripts gets versioned JSON from terraform version, which makes it easier to notice when the format changes later.
- Teams staying on 1.16 for now still get the Go 1.26.10 certificate change through 1.16.7.
If you run self-managed Terraform Enterprise or a shared terraform-mcp-server, check the two bulletins above first. They matter more than anything in the 1.17 changelog.
Cohash writes and maintains Terraform for clients: module design, state clean-up, version upgrades. Our Terraform platform page has the detail. If you'd rather staff it yourself, hire Terraform engineers through us, or ask for a free assessment of your code, state and pipelines first. The DevSecOps practice handles pipelines and policy.
What to take from this
- 01
1.17.0 shipped October 21, 2026. HashiCorp lists no special upgrade steps.
- 02
Const variables and locals now work in required_providers when they're known before planning.
- 03
-minimal-refresh saves API calls but hides drift on untouched resources. Put a full plan in front of production applies.
- 04
Terraform Policy is GA for -policies in the CLI, even though the policy docs still said beta on October 22.
- 05
Before rollout, check whatever parses terraform version -json and any certificate chain through the eMudhra intermediates.
01Is upgrading from Terraform 1.16 to 1.17 a breaking change?
HashiCorp doesn't treat it as one. It's a 1.x minor release that keeps the v1.0 compatibility promises, and the upgrade guide lists no special steps. The things we'd still check are tools that parse terraform version -json, new warnings from ephemeral renewals, log and pow erroring on infinity, and certificate chains affected by Go 1.26.10.
02What does terraform plan -minimal-refresh do?
It refreshes only what Terraform plans to change, so a large state makes fewer API calls. The catch: anything changed outside Terraform on the other resources goes unseen. It won't combine with refresh-only mode or -refresh=false, and HashiCorp says to leave it off during provider upgrades.
03Can I use variables in required_providers now?
In 1.17 you can, as long as the values are known before planning. Use input variables declared with const = true, or locals built from them, for source and version. Resources and data sources won't work there.
04Is Terraform Policy generally available?
The 1.17.0 changelog says so for the CLI's -policies flag. HashiCorp's policy docs still showed a beta note on October 22, 2026. Ask HashiCorp before you gate production on it.
05Do the two 2026 bulletins covered here affect the Terraform CLI?
No, neither does. HCSEC-2026-17 is in self-managed Terraform Enterprise (fixed in 2.0.4 and 1.2.4) and HCSEC-2026-23 is in terraform-mcp-server 0.2.1 through 1.0.0 (fixed in 1.1.0). The CLI had its own fixes, mind you: 1.15.9 updated go-slug for CVE-2026-14978, and 1.17.0 and 1.16.7 ship Go 1.26.10 for CVE-2026-111943.
Three questions, about a minute
Pick an answer and we'll tell you if it's right, and why it is or isn't. The score stays in this browser.
-
Q1Your production pipeline plans with -minimal-refresh, and someone changed a security group by hand in the console. What will the plan show?
show the answer
B. If you didn't change that resource in code, the plan won't show the drift Instances with no planned change skip the refresh under minimal refresh, so a change made outside Terraform to one of them won't appear. That's why production applies should still get a full-refresh plan.
-
Q2Dev and prod use different private registry organizations. What can required_providers reference in 1.17 to pick the right one?
show the answer
D. A const input variable or a local built from one Terraform needs the value before planning. Const variables and locals qualify; resources and data sources don't.
-
Q3Next sprint brings a new AWS provider and a new Terraform core. How do you sequence them?
show the answer
A. Upgrade providers separately and plan without -minimal-refresh During provider upgrades HashiCorp wants a full refresh, without -minimal-refresh or -refresh=false, so schema changes reach state. And one change at a time keeps plan differences easy to explain.