Terraform 0.7

Terraform 0.7

Aug 02 2016    Mitchell Hashimoto

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

Terraform continues to be HashiCorp's fastest growing project. Over the past year, we've released over 20 minor versions of Terraform expanding resource and provider coverage as well as fixing bugs. Terraform 0.7 is the first new major feature release in a year.

Terraform 0.7 adds new functionality to Terraform. Highlights include:


We want to thank our growing community for the continuous stream of improvements, fixes, and ideas. We know that Terraform has grown extremely fast and we've fallen behind at times with issues and pull requests, but we're grateful to the community for being responsive and enthusiastic about improving Terraform.

Terraform now has over 500 contributors with over a dozen core committers. As with most Terraform releases, the bulk of the changes are due to the large amount of contributions we receive from the community.

In addition to pure code contributions, the community has done a wonderful job being responsive and thoughtful in their interactions on the mailing list, conferences, and more.

Thank you Terraform community!


Terraform 0.7 brings the ability to import existing infrastructure resources into Terraform.

For this release of Terraform, import can only import one resource at a time into the state. Terraform doesn't generate configuration. Over time, we expect to expand on this feature to generate configuration, import multiple resources, and more. We'd like to stress that import is a complex feature and Terraform 0.7 is the first iteration of this feature.

This now makes it possible to gradually adopt Terraform into an existing infrastructure. The usage of import is simple:

$ terraform import aws_instance.foo i-abcd1234 …

In the example above, an AWS instance is imported with the given ID. This communicates with the AWS API, finds that instance, and adds it to the Terraform state.

As mentioned earlier, import in its current form will not automatically generate configuration for you. If you import and immediately terraform plan, you'd see that Terraform plans to destroy that resource because it doesn't see a configuration for it. By manually adding a configuration to match the resource, Terraform will not show any changes planned, completing a successful import.

Data Sources

A big source of pain in Terraform historically has been handling read-only resources. These are resources that didn't quite fit the create-read-update-delete model of Terraform resources. For example: Consul keys, AWS AMIs, etc.

In Terraform 0.7, we've introduced a new feature to bring data-only resources as a first class type in Terraform configurations: data sources.

Data sources allow external data to populate Terraform configurations. This data is always loaded on refresh and available for a plan. By converting existing read-only resources to data sources, your terraform plan output will have a lot less <computed> and be a lot more useful!

Data sources feel a lot like a resource:

data "aws_ami" "nat" { most_recent = true

filter { name = "owner-alias" values = ["amazon"] }

filter { name = "name" values = ["amzn-ami-vpc-nat*"] } }

output "ami" { value = "${data.aws_ami.nat.image_id}" }

In the example above we're querying AWS for the most recent NAT AMI and writing it as an output. After running terraform apply you can see the value:

$ terraform apply ...


ami = ami-bae80fd7

Terraform 0.7 ships with a number of data sources right away such as aws_ami. Over time, we expect the community to add hundreds of new data sources. And, as always with Terraform, you can write plugins to add your own data sources.

Read the documentation on data sources to learn more.

State Management CLI

We've introduced a rich set of subcommands for inspecting and modifying Terraform state safely: terraform state.

The commands can be used to list resources in the state, rename resources, move resources into and out of modules, and more. The goal of these commands is to avoid any manual modification of Terraform state files.

The example below lists resources in the state:

$ terraform state list aws_instance.foo aws_instance.bar[0] aws_instance.bar[1] module.elb.aws_elb.main

You can also rename or move resources and modules. The example below renames a single resource:

$ terraform state mv aws_instance.foo aws_instance.bar

The next example moves a single resource into a module:

$ terraform state mv aws_instance.foo module.web

The final example moves a module into a completely different state file. This is an advanced refactoring option that is useful when splitting Terraform configurations into multiple states.

$ terraform state mv -state-out=other.tfstate \ module.web module.web

In addition to the examples shown above, you can show the attributes for a single resource, you can remove items from the state, and more.

The output of the commands are purposely simple and line-oriented to be friendly for Unix-like tools. And these commands, unlike any others in Terraform, produce timestamped backups of the state file for every option. This lets you rollback to any point during a complex series of state modifications. Both of these properties allow the state management CLI to be used in scripts safely.

List and Map Types

You can now represent lists and maps as first class data types in Terraform configurations.

Terraform users would previously fake lists using a combination of split and join functions. While this worked for simple cases, it broke down in more complex scenarios very quickly. In Terraform 0.7, lists and maps are first class types solving many of these problems.

Example usage is shown below:

» main.tf

variable "allowed_cidr_blocks" { type = "list" }

module "appsecuritygroup" { source = "./appsecuritygroup" allowed_cidr_blocks = "${var.cidr_blocks}" }

» appsecuritygroup/sg.tf

variable "allowed_cidr_blocks" {}

resource "aws_security_group" "app" {

» allow all egress

egress { from_port = 0 to_port = 0 protocol = -1 cidr_blocks = [""] }

» only allow ingress from specified cidr blocks

ingress { from_port = 0 to_port = 0 protocol = -1 cidr_blocks = "${var.allowed_cidr_blocks}" } }

In the above config, you can see we're declaring the allowed_cidr_blocks variable with the "list" type and passing it directly into the module.

Here is an example of providing a value for this variable in a flag:

terraform plan -var 'allowed_cidr_blocks=["", ""]'

Values for lists and maps can also be passed via variable files and environment variables. Read more about lists and maps in the v0.7 Upgrade Guide.


Terraform growth has been explosive. We're seeing large commercial interest as well huge growth in the community. We're excited to ship Terraform 0.7 with a strong set of features to empower that adoption further.

We're committed to shipping minor releases of Terraform on a regular cadence, so you can expect Terraform 0.7.1 and onwards to come in the next month as we continue to improve Terraform.

Go download Terraform and give it a try!