HashiCorp Terraform 0.9

We've released Terraform 0.9. Terraform is a tool for safely and efficiently building, combining, and launching any infrastructure.

Since our last major Terraform release, we had 8 minor releases to add and improve hundreds of resources and dozens of providers and the number of community contributors has increased from 750 to just over 900.

Terraform 0.9 adds major new functionality to Terraform. Highlights include:


Terraform 0.9 has no core backwards incompatibilities, but includes deprecations and changes that should be addressed as soon as possible. Please review the upgrade guide. The upgrade guide goes over all the necessary considerations when upgrading to 0.9.

In addition to these changes, the release has a number of changes to providers and resources which could impact you depending on your usage. Minor changes to providers and resources exist in almost every release. Please see the changelog for more information.

Destroy Provisioners

Terraform 0.9 adds support for running provisioners when a resource is destroyed.

Since the initial 0.1 release, Terraform has supported provisioners as a mechanism for performing logic locally or remotely as part of resource creation. Destroy provisioners enhance this to do the same as part of resource destruction.

resource "aws_instance" "consul" {
  # ... other fields

  provisioner "remote-exec" {
    command = "consul leave"
    when = "destroy"

The example above performs a consul leave on destruction of the aws_instance.consul resource. Notice that the syntax for destroy provisioners is identical to standard provisioners with the addition of the when setting.

If a destroy provisioner fails, it will cancel the destruction of the resource. Terraform can be configured to ignore errors as well. Read more about destroy provisioners in the documentation.

State Locking

Terraform will now lock the state for supported backends to prevent multiple concurrent writes. This makes Terraform safer to use in team environments by reducing the risk of one teammember overwriting the work of another.

Terraform will automatically lock your state if the backend supports it. If locking fails, Terraform will not allow you to continue without resolving the issue or disabling state locking (not recommended). If unlocking fails, Terraform will note a lock ID and metadata that can be used to force unlock if necessary.

Local state, AWS, and Consul backends support locking in Terraform 0.9. More support for advanced locking in other backends will be added in 0.9.x releases. For local state, a local file lock is held using OS-specific APIs. This prevents inadvertently running Terraform in parallel locally.

Read the documentation on state locking to learn more.

Interruptable Provisioners

Terraform now supports interrupting all long-running provisioners.

Terraform has always supported Ctrl-C to gracefully interrupt a running operation such as refresh, plan, or apply. In prior versions, Terraform would wait for a provisioner to complete as part of this process. For long-running provisioners, this could be minutes or hours for a graceful exit.

In Terraform 0.9, all provisioners are now interrupted immediately and the resource is tainted (marked for recreation on the next run).

State Environments

Terraform supports a new concept known as a "state environment". A state environment is a state namespace that allows a single folder of Terraform configurations to manage multiple distinct sets of infrastructure resources.

Environments are similar to branches in a version control system, except state environments can not be merged. They are useful for isolating a set of resources to test changes during development. Any changes will have to be re-applied to any other environments.

Environments are managed using the CLI:

$ terraform env list
* mitchellh-test

$ terraform env select default
Switched to environment "default"!

$ terraform env delete mitchellh-test
Deleted environment "mitchellh-test"!

You can reference the current environment using the new ${terraform.env} interpolation. This can be used to make minor changes to your configuration based on the environment:

resource "aws_instance" "example" {
  count = "${terraform.env == "default" ? 5 : 1}"

  tags { Name = "web - ${terraform.env}" }

  # ... other fields

You can learn more about state environments in the documentation page.

Remote State Revamp

Remote state is a critical part of using Terraform safely. Terraform 0.9 introduces big changes and improvements to how remote state is managed, all while being backwards compatible with existing remote state.

All the changes below are backwards compatible. Your existing remote state will continue to work. Terraform will show a warning recommending you update to the new configuration format below. We'll remove support for legacy-configured remote state in a couple major releases (Terraform 0.11).

The first major improvement is state locking, covered in its own dedicated section above. Additionally, we've made numerous improvements to remote state workflow, configuration, safety, and security.

Remote state is now part of "backends", a new abstraction in Terraform to encapsulate various pluggable functionality (such as state environments).

Backend configuration is done via the Terraform configuration:

terraform {
  backend "consul" {
    address = "demo.consul.io"
    path    = "tfdocs"

Initialization and setup is now centralized in a single easy-to-use command terraform init. This command should become the go-to setup command for every team member to run for every Terraform configuration. It is safe to run multiple times and ensures your backend is properly configured.

As part of initialization, Terraform now detects any changes to your backend configuration and offers to migrate your existing state. This lets you easily move from one backend type to another and have Terraform automatically manage this change.

All Terraform commands now work seamlessly with remote state from primary commands such as terraform plan to helper commands like terraform taint or terraform console. When you run one of these commands from your local machine, it automatically runs against the remote state rather than local state. That way users can use the CLI they are comfortable with, but still gain the benefits of remote state storage in team settings.

And finally, we've introduced multiple improvements to increase safety around remote state. For years, Terraform has checked serial numbers to prevent overwriting future work. Terraform 0.9 now also checks the lineage of the state to ensure the state hasn't completely changed underneath you. State lineage is a unique ID assigned upon creation of state. If state lineage differs, it means the states are completely different (and serial numbers are meaningless).

These changes should dramatically improve the user experience and user confidence in remote state, and we have more exciting updates planned.

Read the full backend documentation to learn more.


Terraform ships provider updates alongside every minor release. As part of Terraform 0.9, we want to highlight some of the bigger recent changes.

Timeouts are now a standardized part of the framework used to write resources. Timeouts enable you to configure the create, read, update, and delete timeouts for resources. They are currently only supported by a couple resources, but we're working to quickly expand support for more. Example:

resource "aws_rds" "db" {
  # ... other fields

  timeouts {
    create = "10m"

Interrupts can now be detected and handled with custom logic in resources. Only a handful of resources currently listen for interrupts but more will be added soon. This allows long-running resources to be quickly interrupted with a Ctrl-C. As resources implement timeouts, they'll soon also support interrupts automatically.

New providers and resources: Terraform supports dozens of new providers and hundreds of new resources. There are too many to list here! Search "New provider" or "New resource" in the changelog.

Huge improvements to existing resources. For example: AWS instances can be resized without forced destruction. We have full IPv6 support for EC2. The DNSimple provider was updated to use APIv2 while only requiring a new auth token. And many more. These are improvements that come thanks to the community working to improve Terraform for everyone everyday.


It is exciting to watch Terraform mature with every release. The community is growing and so is the team here at HashiCorp.

We will continue to ship minor releases of Terraform on average every two weeks, so you can expect 0.9.1 and onwards throughout the coming weeks. At the same time, we are already beginning development on Terraform 0.10.

Go download Terraform and give it a try!

Sign up for the latest HashiCorp news

By submitting this form, you acknowledge and agree that HashiCorp will process your personal information in accordance with the Privacy Policy.