Terraform 1.12 adds native OCI state storage and locking
Terraform 1.12 adds an Oracle Cloud Infrastructure Object Storage backend and separates test-run concurrency from parallel operations inside a run.
Shared Terraform state needs coordination as well as storage. Putting a state file in an object store makes it reachable by multiple clients, but those clients still need a way to avoid conflicting updates. Terraform 1.12.0, released on May 14, adds a native backend for Oracle Cloud Infrastructure Object Storage. The backend implements locking through the object store's conditional-write behavior, alongside workspace-aware state paths.
I use Terraform as a general abstraction over infrastructure APIs, so support for another backend is useful when it preserves the same operational expectations. The important addition is a defined relationship between state identity and exclusive access. An object upload alone would leave too much of that relationship to external convention.
The backend identifies a state object
The OCI backend documentation identifies the bucket and object-storage namespace as required configuration. A key chooses the state object's path. Default-workspace state uses that key directly, while other workspaces add a workspace prefix and name. The configured location therefore determines which shared state a client will read and update.
This example assumes an existing bucket and appropriate OCI authentication. It supplies the state location without embedding a private key in the configuration.
terraform {
backend "oci" {
bucket = "infra-state"
namespace = "example-namespace"
region = "us-ashburn-1"
key = "network/terraform.tfstate"
}
}
Those identifiers are operational inputs. Two directories configured to use the same location are addressing the same state, regardless of how their source trees are organized. Conversely, changing the key changes the addressed object. A naming scheme should communicate the management boundary represented by each state instead of depending on directory names that the backend does not receive.
Conditional creation coordinates the lock
The backend client implementation creates a separate lock object using an If-None-Match condition. The condition asks the service to create the object only when the addressed object does not already exist. This puts the decision at the storage service, where competing clients can encounter the same object identity.
A client-side existence check followed by an unconditional write would leave a gap between the two requests. Another client could observe the same absence during that gap. Conditional creation makes the write itself depend on absence, which is the property needed to make a shared lock meaningful.
The separate lock object also explains why permissions for the backend include more than reading and writing the state body. The client needs to manage the coordination object for the same state location. Storage access policy should describe both responsibilities so that a successful state read does not conceal an inability to acquire or release a lock.
Terraform's state-locking documentation explains that supporting backends lock operations that could write state. Failure to acquire the lock prevents continuation. The lock is coordination among clients using that mechanism, and should be treated as part of the backend operation rather than an optional file-cleanup task.
Recovery and exclusion address different failures
The OCI documentation recommends bucket versioning for recovery from accidental deletion or human error. That recommendation complements locking. A lock prevents a class of simultaneous operations, while retained object versions provide earlier contents that may be needed after a bad change. Neither mechanism establishes that the desired infrastructure configuration is correct.
This distinction affects how the backend should be evaluated. A demonstration that two clients cannot hold the same lock says something about exclusion. A demonstration that an earlier state object remains available says something about recovery. Treating one successful demonstration as proof of both properties would overlook a separate failure mode.
The state object also remains a management artifact with its own access requirements. Terraform's state overview describes the bindings between resource instances and remote objects. Restoring an older copy can restore older bindings, which is different from reverting the remote infrastructure itself. Recovery has to account for the relationship between the saved record and the objects that currently exist.
Test execution has two levels of concurrency
The same release adds test controls that are easy to confuse. The test command reference documents -parallelism as a limit on operations inside a single test run's plan or apply. It is useful when a module contains many independent resource operations but the execution environment or remote API needs a smaller active workload.
For example, this invocation asks each run to use a parallelism limit of two. It does not, by itself, opt multiple run blocks into concurrent execution.
terraform test -parallelism=2
The test-language documentation defines the other control. Run blocks remain sequential by default. Setting parallel = true makes eligible runs available for parallel execution. Eligibility depends on their relationships, including whether they reference each other's outputs and whether they share a state file.
Two runs against the same module configuration need distinct state keys to run in parallel. A run that consumes another run's output has an ordering dependency even when both are marked parallel. This lets the test describe independence explicitly without discarding the sequencing required by its data and state relationships.
I prefer this separation because it keeps a performance choice connected to the operation it affects. Independent test cases and independent resource operations are different forms of parallel work. A single switch that blurred them would make the resulting load and ordering harder to understand.
Separate test state does not isolate external names
The command reference explains that tests maintain state separately from the configuration's existing state and attempt cleanup after execution. Tests can still create real infrastructure. Independent state keys therefore do not establish that two tests can safely use the same externally unique object name or other shared service constraint.
This is a practical implication of parallel execution. State separation gives Terraform distinct records of the test resources. The remote service still receives their actual names and requests. A module test intended to run alongside another needs inputs that remain valid under that overlap, with dependencies encoded when the cases are not independent.
The release adds both a backend coordination mechanism and more expressive test scheduling. They address different workloads, but both require a precise definition of what is shared. For the OCI backend it is the state location and its lock object. For tests it is the state key and the run dependencies, alongside whatever constraints the remote infrastructure imposes.