Reference¶
Scope
Look-up facts for OpenTofu: release and support matrix, features by version, CLI flags and environment variables that differ from Terraform, state-encryption key providers and methods, backends and locking, provider protocol RPCs, security advisories, a hardening checklist, and rough performance figures. For tasks see How-to Guides. For internals see Explanation.
Release and Support Matrix¶
OpenTofu has no fixed release cycle. The support period of each minor series is written at the top of that series' CHANGELOG.md (RELEASE.md).
| Series | First GA (date) | Latest patch seen (2026-09-25) | Supported until | Status (2026-09-25) |
|---|---|---|---|---|
| 1.14 | Not released | main branch, "1.14.0 (Unreleased)" |
2028-02-01 | In development |
| 1.13 | Not released: v1.13.0-rc1 is out for testing (2026-09) |
1.13.0-rc1 | 2027-08-01 | Release candidate |
| 1.12 | 1.12.0 (2026-05-14) | 1.12.6 (2026-08-19). The branch changelog lists 1.12.7 as unreleased. | 2027-02-01 | Current stable |
| 1.11 | 1.11.0 (2025-12-09) | 1.11.14 | 2026-08-01 | End of support |
| 1.10 | 1.10.0 (2025-06) | 1.10.10 | TBD: not stated in the v1.10 changelog | Superseded |
| 1.9 | 1.9.0 (2025-01) | 1.9.4 | TBD | Superseded |
| 1.8 | 1.8.0 (2024-07-29) | 1.8.11 | TBD | Superseded |
| 1.7 | 1.7.0 (2024-04-30) | TBD | TBD | Superseded |
| 1.6 | 1.6.0 (2024-01, first GA) | TBD | TBD | Superseded |
Where these dates come from
Support dates come from the vX.Y branch changelogs. GA dates come from the OpenTofu release blog posts plus a second source: InfoQ for 1.12.0, AlternativeTo for 1.11.0, InfoQ/DEV for 1.10.0, env0/InfoQ for 1.9.0, the Linux Foundation press release for 1.7.0, and Terrateam/Spacelift for 1.8.0. The 1.12.6 date comes from the GitHub release page, as reported by newreleases.io. Rows marked TBD could not be checked because GitHub release pages are blocked from this environment.
Features by Version¶
| Version | Headline features | Breaking or upgrade notes |
|---|---|---|
| 1.6 | First GA of the fork. Adds tofu test and the OpenTofu Registry (registry.opentofu.org). |
None. It is a drop-in replacement for Terraform 1.5.x. |
| 1.7 | State and plan encryption. Provider-defined functions. removed block. Loopable (for_each) import blocks. |
None noted |
| 1.8 | Early variable/locals evaluation in backend blocks, module sources and encryption config. Provider mocking and resource overrides in tofu test. .tofu override files. |
Removed the S3 backend's use_legacy_workflow |
| 1.9 | Provider for_each (aliased providers only). -exclude flag. encrypted_metadata_alias. tofu init prompts for early-eval variables. -show-sensitive, -consolidate-warnings and -consolidate-errors. |
Deprecated using ghcr.io/opentofu/opentofu as a base image |
| 1.10 | OCI registry support for providers (oci_mirror) and modules (oci://). Native S3 locking (use_lockfile). Experimental OpenTelemetry tracing. -target-file and -exclude-file. Global provider cache lock. Experimental deprecation of variables and outputs. moved across resource types. removed with lifecycle and provisioners. external key provider. New built-in functions decode_tfvars, encode_tfvars and encode_expr. -concise. |
Needs Linux kernel 3.2+ and macOS 11+. The pg backend changed its locking, so do not mix 1.10 with older versions on one database. The Docker image can no longer be used as a base image. |
| 1.11 | Ephemeral resources, variables and outputs and write-only attributes. lifecycle { enabled = ... } meta-argument. S3 backend object tags. |
Removed azurerm endpoint and msi_endpoint. SHA-1 signatures are rejected for TLS and SSH. Mocks must match provider schemas. issensitive() returns unknown for unknown values. |
| 1.12 | prevent_destroy can reference variables. lifecycle { destroy = false }. The registry serves both h1: and zh: hashes, so tofu init records every platform. -json-into=FILE. Concurrent provider downloads. import by resource identity. language block. const variables. Warnings for attributes the provider schema marks deprecated. local backend writes pretty-printed JSON. |
WinRM provisioner connections deprecated. OPENTOFU_USER_AGENT removed. Last series that supports macOS 12. Expect extra h1: lines in lock files. |
| 1.13 (RC) | Experimental Symbol Libraries (language { experiments = [symbol_libraries] }). Experimental -lint. convert() and assume...() functions. Windows ARM64 builds. Saved plans embed provider schemas. aws_kms gains encryption_context, gcp_kms gains AAD, and openbao gains associated_data. tofu providers lock -oci-mirror. |
WinRM removed. Needs macOS 13+. Last series with 32-bit (386, arm) builds. base64gzip output changes but still decompresses to the same bytes. |
| 1.14 (dev) | tofu plan groups repeated warnings into one. mock_provider gains a source argument. |
No official 32-bit builds |
Sources: the v1.7 to v1.12 "What's new" pages (1.12, 1.11, 1.10, 1.9), and the v1.13 and main changelogs.
OpenTofu vs Terraform: Feature Differences¶
| Feature | OpenTofu | Terraform |
|---|---|---|
| License | MPL-2.0 | BSL 1.1 since 1.6 (August 2023) |
| Steward | Linux Foundation project, CNCF Sandbox since 2025-04-23 | HashiCorp, an IBM company |
| Client-side state and plan encryption | Yes, since 1.7 | No. Relies on backend or HCP Terraform encryption at rest. |
| Variables in backend and encryption blocks (early evaluation) | Yes, since 1.8 | No |
Variables in module source / version |
Yes, since 1.8 | Yes, since 1.15 |
Provider for_each |
Yes, since 1.9 | No |
-exclude planning flag |
Yes, since 1.9 | No |
| OCI registry distribution of providers and modules | Yes, since 1.10 | No |
.tofu override files |
Yes, since 1.8 | Not applicable |
| Ephemeral resources and write-only attributes | Yes, since 1.11 | Yes (Terraform added them first) |
| Public registry | registry.opentofu.org, searchable at search.opentofu.org |
registry.terraform.io |
| Provider plugin protocol | gRPC tfplugin5 / tfplugin6 |
Same, so provider binaries are shared |
Terraform-only features
Features that Terraform added after the fork, and that OpenTofu has not implemented, will not work under tofu. HCP Terraform-specific workflows are one example. Check the migration guide before switching a configuration that targets Terraform 1.6 or later.
CLI Flags and Commands Specific to OpenTofu¶
| Flag / command | Applies to | Since | Purpose |
|---|---|---|---|
-exclude=ADDR |
plan, apply | 1.9 | Skip the given resources. The opposite of -target. |
-target-file=FILE / -exclude-file=FILE |
plan, apply | 1.10 | Read target or exclude addresses from a file, one per line, # comments allowed |
-show-sensitive |
plan, apply, others | 1.9 | Show sensitive values in output |
-consolidate-warnings / -consolidate-errors |
most commands | 1.9 | Group similar diagnostics |
-concise |
plan, apply | 1.10 | Shorter output for automation |
-json-into=FILE |
most commands | 1.12 | Write machine-readable JSON to a file while the terminal keeps human-readable output |
-deprecation=module:all (or module:local, module:none) |
plan and other commands | Documented by 1.12 (first version TBD) | Choose which modules produce deprecation warnings (default module:all) |
-suppress-forget-errors |
destroy | 1.12 | Exit 0 when resources are forgotten instead of destroyed |
-lock=false, -lock-timeout= |
console | 1.12 | Control state locking in tofu console |
-lint |
supported commands | 1.13 (experimental) | Run the built-in lint rules |
tofu providers lock -oci-mirror=... |
providers lock | 1.13 | Lock hashes from an OCI mirror |
Environment Variables¶
| Variable | Purpose |
|---|---|
TF_ENCRYPTION |
Encryption configuration in HCL or JSON. It is merged with the code configuration, and its values win. |
TF_PLUGIN_CACHE_DIR |
Shared provider cache. Since 1.10 it has a filesystem lock, so concurrent runs can share it. |
TF_LOG, TF_LOG_PATH |
Debug logging. Since 1.13 it also carries OpenTelemetry library log lines. |
OTEL_TRACES_EXPORTER=otlp, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_INSECURE |
Turn on experimental tracing (1.10+). Traces go only to the collector you configure. |
BROWSER |
Browser used by tofu login on Unix (1.12+) |
TF_VAR_<name>, TF_CLI_ARGS*, TF_DATA_DIR, TF_WORKSPACE |
Same meaning as in Terraform |
File Names and Extensions¶
| Terraform name | OpenTofu-only override (1.8+) | Notes |
|---|---|---|
foo.tf |
foo.tofu |
When both exist, OpenTofu ignores foo.tf |
foo.tf.json |
foo.tofu.json |
|
foo_override.tf |
foo_override.tofu |
|
foo.tftest.hcl |
foo.tofutest.hcl |
Test files |
foo.tftest.json |
foo.tofutest.json |
|
.terraform.lock.hcl |
Same name | Provider addresses are recorded as registry.opentofu.org/... |
terraform.tfstate |
Same name | Same JSON format. Encrypted state is an envelope that Terraform cannot read. |
State Encryption Reference¶
Configure encryption in terraform { encryption { ... } } or through TF_ENCRYPTION. Every setup has three parts: one or more key_provider blocks, a method block, and state, plan and remote_state_data_sources targets (docs).
Key providers¶
| Key provider | Since | Required options | Notes |
|---|---|---|---|
pbkdf2 |
1.7 | passphrase (at least 16 characters) or chain |
Defaults: key_length 32, iterations 600,000 (minimum 200,000), salt_length 32, hash_function sha512 (sha256 also allowed, sha1 not) |
aws_kms |
1.7 | kms_key_id, key_spec (for example AES_256), plus region and credentials |
Authenticates like the S3 backend. encryption_context is added in 1.13. |
gcp_kms |
1.7 | kms_encryption_key, key_length (1 to 1024) |
Authenticates like the GCS backend. AAD is added in 1.13. |
openbao |
1.7 | key_name (transit key) |
Optional token (or BAO_TOKEN), address (or BAO_ADDR), transit_engine_path (default /transit), key_length (default 32). associated_data is added in 1.13. |
azure_vault |
Documented in v1.12 (first version TBD) | vault_uri, vault_key_name, key_length |
Always uses Entra ID. symmetric plus symmetric_key_size for Managed HSM. |
external |
1.10 (experimental) | command (argv list) |
Runs an external program, such as a password manager CLI. Can be chained. |
Every key provider also accepts encrypted_metadata_alias (1.9+). It sets a fixed metadata key, so you can rename the key provider later.
Methods¶
| Method | Notes |
|---|---|
aes_gcm |
The only built-in encryption method. Needs a 16, 24 or 32-byte key. Suffers from "key saturation", so use PBKDF2 with a strong passphrase or a KMS that rotates keys. |
external |
Experimental. An external program does the encryption. |
unencrypted |
Explicit no-op, used only as a fallback while migrating to or from encryption |
Target blocks¶
| Block | Options |
|---|---|
state { } |
method, enforced = true (refuse to write plaintext), fallback { method = ... } |
plan { } |
Same options as state |
remote_state_data_sources { default { method = ... } remote_state_data_source "name" { ... } } |
Decrypt state read through terraform_remote_state |
Compatibility guarantee
OpenTofu keeps each documented key provider and method for at least one more minor version after it is deprecated, and prints a warning on plan and apply. Do not rename key providers or methods once data is encrypted unless you set encrypted_metadata_alias or use a fallback block.
Backends and State Locking¶
| Backend | Locking | Notes |
|---|---|---|
local |
Yes (OS file locks) | Default. Writes terraform.tfstate. Pretty-printed JSON since 1.12. |
s3 |
DynamoDB table (dynamodb_table) or a native lock file (use_lockfile = true, 1.10+, uses S3 conditional writes) |
Both can be on at once during migration. Supports object tags (1.11+) and aws login credentials (1.12+). |
gcs |
Yes (lock object) | Google Cloud Storage |
azurerm |
Yes (blob lease) | Supports customer-provided and customer-managed keys (1.12+) and Azure DevOps workload identity federation (1.12+) |
pg |
Yes (PostgreSQL advisory locks) | Locking changed in 1.10. Custom table names since 1.10. |
kubernetes |
Yes | Stores state in a Secret |
consul |
Yes | Stores state in the Consul KV store |
cos |
Yes | Tencent Cloud Object Storage |
oss |
Yes | Alibaba Cloud OSS |
http |
Optional (needs lock_address / unlock_address) |
force-unlock supported since 1.10 |
remote |
Handled by the remote service | For TFE/TACOS-compatible APIs |
Backends that Terraform removed in 1.3 (artifactory, etcd, etcdv3, manta, swift) are not in the OpenTofu docs either.
Dependency Lock File Hashes¶
| Prefix | What it hashes | Where it comes from |
|---|---|---|
zh: |
SHA-256 of the provider's distribution .zip archive ("zip hash") |
The registry's SHA256SUMS for every platform |
h1: |
Hash of the unpacked package contents ("hash scheme 1") | Computed locally, and served by the OpenTofu registry since 1.12 |
Since 1.12, tofu init records h1: and zh: hashes for all platforms. In most cases you no longer need tofu providers lock for cross-platform teams. The first init after upgrading adds new h1: lines. That is expected.
Provider Protocol RPCs¶
Providers are separate processes that speak gRPC protocol 5 (tfplugin5) or 6 (tfplugin6). Some RPCs have different names in the two versions.
| RPC (v6 name / v5 name) | Purpose |
|---|---|
GetProviderSchema / GetSchema |
Returns provider, resource, data source, ephemeral resource and function schemas |
ValidateProviderConfig / PrepareProviderConfig |
Validates the provider configuration and fills in defaults |
ValidateResourceConfig / ValidateResourceTypeConfig |
Validates one resource's configuration |
ConfigureProvider |
Passes credentials, region and other provider settings |
UpgradeResourceState |
Migrates stored state from older schema versions |
ReadResource |
Refreshes one resource's real-world state |
PlanResourceChange |
Computes the proposed new state |
ApplyResourceChange |
Creates, updates or deletes the object |
ImportResourceState |
Imports an existing object |
ReadDataSource |
Reads a data source |
GetResourceIdentitySchemas / UpgradeResourceIdentity |
Resource identity, used by import { identity = ... } in 1.12+ |
MoveResourceState |
Moves state across resource types (used by moved, 1.10+) |
OpenEphemeralResource / RenewEphemeralResource / CloseEphemeralResource |
Ephemeral resource lifecycle (1.11+) |
CallFunction |
Provider-defined functions (1.7+) |
Source: the plugin protocol docs and the tfplugin*.proto files in the same directory. The newest file in the v1.12 branch is tfplugin6.10.proto. It also defines RPCs for list resources, actions and pluggable state stores, which track Terraform's protocol. This page has not verified whether OpenTofu core calls them (TBD).
Platform Requirements¶
| Platform | Requirement |
|---|---|
| Linux | Kernel 3.2+ (1.10+) |
| macOS | 11+ (1.10 to 1.12). 13 Ventura+ (1.13+). |
| Windows | amd64. ARM64 is officially supported from 1.13. |
32-bit (386, arm) |
Built up to 1.13. Dropped in 1.14. |
| Docker | ghcr.io/opentofu/opentofu:<tag>-minimal images exist only so you can copy the binary into your own image (1.10+) |
Security Advisories (v1.12 Series)¶
| Fixed in | Issue |
|---|---|
| 1.12.1 | Hangs or panics over SSH. Revoked CA SignatureKey not checked. |
| 1.12.2 | Crafted JWE could hang or panic the OpenBao key provider (wrapping algorithms). Unescaped bytes in SSH errors. High CPU use against an attacker-controlled server. |
| 1.12.3 | Arbitrary file read during git operations through a crafted module URL |
| 1.12.5 | Go stdlib Encrypted Client Hello leaked PSK identities |
| 1.12.6 | Credentials re-sent to the target of a redirect from an OCI registry. CPU/memory exhaustion from crafted relative URLs returned by an attacker-controlled backend or registry. |
| 1.12.7 (unreleased) | A malicious SSH server could deadlock remote-exec and file provisioner connections |
Source: the v1.12 CHANGELOG. Report vulnerabilities through GitHub Private Vulnerability Reporting (SECURITY.md).
Provider Credential Sources (AWS Example)¶
These are the usual AWS provider credential sources, roughly in the provider's precedence order.
| Order | Source | Recommended for |
|---|---|---|
| 1 | Static credentials in the provider block | Never in production |
| 2 | Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) |
CI/CD with short-lived credentials |
| 3 | Shared config and credentials files (~/.aws/config, ~/.aws/credentials), including SSO profiles |
Local development |
| 4 | Container or instance role (ECS task role, EC2 instance profile) | OpenTofu running on AWS compute |
| n/a | assume_role / assume_role_with_web_identity in the provider block (layered on any source above) |
Cross-account access, CI OIDC |
Remote Backend Security Properties¶
| Backend | Encryption at rest | In transit | Locking |
|---|---|---|---|
| S3 | SSE-S3, SSE-KMS, SSE-C (encrypt = true, kms_key_id) |
TLS | DynamoDB or use_lockfile |
| GCS | Google-managed keys or CMEK | TLS | Lock object |
| Azure Blob | Microsoft-managed keys, CMK or CPK | TLS | Blob lease |
| PostgreSQL | Depends on server/disk configuration | TLS (configure sslmode) |
Advisory locks |
| Consul | Depends on Consul configuration | TLS (recommended) | Session locks |
Defense in depth
Backend encryption protects the storage medium. OpenTofu state encryption protects the state content from anyone who can read the bucket. Use both in production.
Security Hardening Checklist¶
- Turn on state and plan encryption with a KMS-backed key provider (
aws_kms,gcp_kms,azure_vault,openbao) - Set
enforced = trueinstate {}andplan {}so plaintext is never written - Back up keys and test decryption before you encrypt production state
- Use a remote backend with state locking for every team environment
- Turn on backend encryption at rest (S3 SSE-KMS, GCS CMEK, and others) and bucket versioning
- Never hardcode provider credentials in
.tffiles. Use OIDC or workload identity, IAM roles, or dynamic secrets. - Prefer ephemeral resources and write-only attributes (1.11+) for secrets so they never reach state
- Commit
.terraform.lock.hclto version control - Mark sensitive variables and outputs with
sensitive = true - Limit local state file permissions to the owner (
chmod 600) - Pin module sources to versions, commit SHAs or OCI digests. Modules are not signature-verified.
- Rotate encryption keys regularly with the
fallbackblock - Stay on a supported series and apply patch releases promptly. The v1.12 series had six security-relevant patches in 2026.
Performance Figures (Unsourced Estimates)¶
Unsourced performance data
Do not plan capacity from these numbers. They are rough estimates from vendor documentation, community reports and engineering judgment. They are not controlled benchmarks: hardware, versions and methods were not recorded. Run your own measurements. The main levers are -parallelism (default 10), provider API rate limits, and splitting state into smaller root modules.
Plan and apply time by state size¶
| State size (resources) | Plan time | Apply time (parallelism=10) |
|---|---|---|
| 50 | < 5 s | 30 s to 2 min |
| 200 | 10 to 30 s | 2 to 5 min |
| 1,000 | 1 to 3 min | 10 to 30 min |
| 5,000 | 5 to 15 min | 30 min to 2 h |
Provider timings¶
| Provider | Init time | Resource create | Notes |
|---|---|---|---|
| AWS | 2 to 5 s | 5 to 30 s per resource | API rate limits apply |
| Azure | 3 to 8 s | 10 to 60 s per resource | Slower API responses |
| GCP | 2 to 5 s | 5 to 30 s per resource | Similar to AWS |
| Kubernetes | 1 to 3 s | 1 to 5 s per resource | Fast for small objects |
State file scaling¶
| Resources | State file size | Refresh time |
|---|---|---|
| 100 | 100 KB to 1 MB | 10 to 30 s |
| 1,000 | 1 to 10 MB | 1 to 5 min |
| 10,000 | 10 to 100 MB | 10 to 30 min |
Rule of thumb (not an OpenTofu limit): once a state file passes tens of MB, split it, because every plan refreshes every resource. Recent releases improved the performance of large graphs (1.9), provider installation (1.10, 1.12) and long depends_on chains (1.13).