Terraform backends make state coordination part of execution
Terraform 0.9 introduces backends, automatic state locking and named state environments. Their guarantees depend on backend capabilities and on how configurations divide ownership.
Sharing a state file does not by itself coordinate the programs that update it. Two Terraform processes can read the same description of infrastructure and each calculate changes without knowing that the other is working. The state storage location answers where the record lives. A lock answers whether another writer can start using that record concurrently. Terraform 0.9 brings those concerns together in its backend abstraction.
The March 15 release notes call remote backends the successor to remote state. Configuration moves into files, initialization uses terraform init, and Terraform stops maintaining a local cache of remote state. The release also introduces automatic state locking for the local, Consul and S3 backends, with DynamoDB supplying the S3 locking mechanism.
I value Terraform as a common language for infrastructure APIs. Its usefulness depends on the record connecting configuration to the objects those APIs manage. State coordination belongs in the execution model because every provider operation depends on a coherent understanding of that ownership.
A backend controls more than a storage address
The backend documentation shipped with 0.9 defines a backend in terms of loading state and executing operations such as apply. This definition permits remote storage and remote execution, but the two are different capabilities. Selecting a backend that stores state remotely does not establish that Terraform will execute provider operations remotely.
The default remains the local backend. A configuration can therefore continue to use Terraform without adopting remote storage. The abstraction changes the organization of the implementation and makes other choices explicit. It does not require every user to operate a separate state service.
Backends retrieve remote state when it is needed and keep it in memory during ordinary operation, according to the documentation. Removing the persistent local cache reduces the number of places where a remote state snapshot normally resides. That benefit should be stated narrowly. Backend configuration has its own storage rules, and those rules still matter when credentials appear among its inputs.
Configuration and initialization become one workflow
A backend declaration belongs inside the top-level terraform block. The configuration reference permits only one backend and prohibits interpolation in its configuration. These restrictions make the backend a distinct initialization concern. It cannot depend on arbitrary values produced by the resource graph whose state it must first load.
The S3 backend illustrates both storage and coordination in one declaration. Its versioned reference names the locking argument lock_table in this release.
terraform {
backend "s3" {
bucket = "example-infrastructure-state"
key = "network/terraform.tfstate"
region = "us-east-1"
lock_table = "terraform-state-locks"
}
}
The bucket and DynamoDB table must already exist. The documentation requires the table to have a primary key named LockID. This example contains location and coordination settings, while authentication remains outside the block. The selected state key determines which stored state the configuration uses.
After adding or changing the declaration, terraform init configures the backend. Terraform can offer to migrate existing state when first adopting a backend or when changing one. This is important because replacing a storage configuration must not implicitly discard the association between existing resources and the configuration that owns them.
The initialization process can also accept partial backend configuration. An author can leave sensitive values out of committed configuration and provide the remaining values interactively or through a configuration file. The reference states that the resulting configuration is stored under .terraform. Keeping a credential out of version control therefore does not mean Terraform never writes that credential to local disk.
That distinction matters when describing the removal of local remote-state caching. State data and backend configuration are separate kinds of information. A statement about where Terraform persists one should not be generalized into a promise about the other.
Locking is automatic when the backend supports it
The locking reference says Terraform locks state for operations that could write it. The lock is automatic. Failure to acquire it prevents the operation from continuing. Users do not need to insert a separate lock command before each apply.
The guarantee remains conditional on backend support. Terraform 0.9 does not turn every remote store into a coordinating service. The release notes identify the supported implementations, and S3 specifically uses a separate DynamoDB table. Merely placing state in an S3 bucket does not supply the locking configuration shown above.
A state lock coordinates Terraform writers using that state. It does not prevent someone from changing a cloud resource directly through its API. Nor does it make a collection of provider API calls an atomic transaction. The lock addresses concurrent access to Terraform's record, which is one particular source of inconsistent decisions.
There is also a distinction between quiet operation and absent protection. The documentation says successful automatic locking need not produce a message. Terraform reports status when acquiring the lock takes longer than expected. An ordinary quiet apply therefore does not establish that locking is disabled.
For an abandoned lock, Terraform provides force-unlock with a unique lock identifier. The reference limits its intended use to a caller's own lock when automatic unlocking failed. Releasing another active writer's lock would reintroduce concurrent writers. The identifier helps target the intended lock, but it cannot determine whether another process is still doing useful work.
I prefer the default to stop when coordination fails. Continuing with an uncertain state owner would make a successful-looking command less informative about the safety of its decisions.
Environments separate state, with limited isolation
Terraform 0.9 also adds named state environments. The environment documentation describes an environment as a state namespace. The same directory of configuration can therefore manage distinct sets of resources by selecting different state records.
Every configuration begins in default, an environment that cannot be deleted. The command family is terraform env, and configuration can refer to the current selection through ${terraform.env}. These are the names used by this release, which matter when reading or writing examples for 0.9.
Selecting a new empty environment changes what Terraform knows about existing objects. Resources managed in another environment continue to exist physically, but they do not appear in the newly selected state's ownership record. A subsequent plan works from the selected environment. It does not infer that similarly described infrastructure in another environment should be adopted automatically.
That has consequences for naming. If a configuration creates externally named objects, state separation alone does not make their names distinct. The documentation shows incorporating ${terraform.env} into names or tags and adjusting counts by environment. The author must still decide which input values need to vary for separate deployments.
The documentation explicitly advises against using environments alone to distinguish development, staging and production. It recommends independently managed configurations connected through terraform_remote_state data sources for that division. Environments are presented as useful for cases such as testing changes associated with a version-control branch.
This guidance limits what the new feature claims to solve. Sharing one configuration and changing its state namespace is convenient when the deployments should have the same structure. A production boundary can also require different ownership and configuration relationships. A namespace cannot express all those relationships merely by having a different name.
Shared state with a local selection
An environment belongs to the backend and can be shared by several users. Its current selection, however, is stored locally under .terraform. Two people can therefore work with different environments while using the same configuration and shared backend. The distinction explains why a local command can affect which remote state subsequent commands use.
Backend migration can copy multiple environments to the destination, with Terraform asking whether to do so. Migrating only the currently interesting state would otherwise leave other deployments associated with the old backend. The configuration reference treats that situation as part of the initialization workflow.
These changes give Terraform a clearer division of responsibility. Backend configuration determines how operations obtain and coordinate their state. An environment determines which state namespace the configuration currently addresses. Provider configuration still determines access to the infrastructure APIs. Understanding those choices separately explains why remote storage, locking and state separation can support each other while providing different guarantees.