Suppose you add an AWS instance to a Terraform configuration. Before creating it, run `terraform plan` to see the proposed change. The command calculates a plan; it does not perform the planned resource actions. Review the result, then apply it if it matches your intent. A plan can also be saved to a file for a later step. section 1.4.3 section 2.1.6
Planning has three subphases:
- Refresh: read infrastructure from the provider and read data sources to detect changes since the previous run. section 1.4.3
- Compare: check the refreshed state against the resources and configuration described in code. section 1.4.3
- Plan: construct a directed acyclic graph (DAG) of actions needed to align them. section 1.4.3
Listing 2.5 Terraform planning with the CLI
data.aws_vpc.default: Reading...
data.aws_ami.ubuntu: Reading...
data.aws_ami.ubuntu: Read complete after 0s [id=ami-0cb81cb394fc2e305]
data.aws_vpc.default: Read complete after 0s [id=vpc-cc5449a4]
data.aws_subnets.default: Reading...
data.aws_subnets.default: Read complete after 0s [id=us-east-2]
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_instance.hello_world will be created
+ resource "aws_instance" "hello_world" {
+ ami = "ami-0cb81cb394fc2e305"
+ arn = (known after apply)
+ associate_public_ip_address = (known after apply)
+ availability_zone = (known after apply)
+ cpu_core_count = (known after apply)
+ cpu_threads_per_core = (known after apply)
+ disable_api_stop = (known after apply)
+ disable_api_termination = (known after apply)
+ ebs_optimized = (known after apply)
+ get_password_data = false
+ host_id = (known after apply)
+ host_resource_group_arn = (known after apply)
+ id = (known after apply)
+ instance_initiated_shutdown_behavior = (known after apply)
+ instance_state = (known after apply)
+ instance_type = "t3.micro"
+ ipv6_address_count = (known after apply)
+ ipv6_addresses = (known after apply)
+ key_name = (known after apply)
+ monitoring = (known after apply)
+ outpost_arn = (known after apply)
+ password_data = (known after apply)
+ placement_group = (known after apply)
+ placement_partition_number = (known after apply)
+ primary_network_interface_id = (known after apply)
+ private_dns = (known after apply)
+ private_ip = (known after apply)
+ public_dns = (known after apply)
+ public_ip = (known after apply)
+ secondary_private_ips = (known after apply)
+ security_groups = (known after apply)
+ source_dest_check = true
+ subnet_id = "subnet-b96b6ed1"
+ tags = {
+ "CreatedBy" = "terraform"
}
+ tags_all = {
+ "CreatedBy" = "terraform"
}
+ tenancy = (known after apply)
+ user_data = (known after apply)
+ user_data_base64 = (known after apply)
+ user_data_replace_on_change = false
+ vpc_security_group_ids = (known after apply)
+ capacity_reservation_specification {
+ capacity_reservation_preference = (known after apply)
+ capacity_reservation_target {
+ capacity_reservation_id = (
known after apply)
+ capacity_reservation_resource_group_arn = (
known after apply)
}
}
+ ebs_block_device {
+ delete_on_termination = (known after apply)
+ device_name = (known after apply)
+ encrypted = (known after apply)
+ iops = (known after apply)
+ kms_key_id = (known after apply)
+ snapshot_id = (known after apply)
+ tags = (known after apply)
+ throughput = (known after apply)
+ volume_id = (known after apply)
+ volume_size = (known after apply)
+ volume_type = (known after apply)
}
+ enclave_options {
+ enabled = (known after apply)
}
+ ephemeral_block_device {
+ device_name = (known after apply)
+ no_device = (known after apply)
+ virtual_name = (known after apply)
}
+ maintenance_options {
+ auto_recovery = (known after apply)
}
+ metadata_options {
+ http_endpoint = (known after apply)
+ http_put_response_hop_limit = (known after apply)
+ http_tokens = (known after apply)
+ instance_metadata_tags = (known after apply)
}
+ network_interface {
+ delete_on_termination = (known after apply)
+ device_index = (known after apply)
+ network_card_index = (known after apply)
+ network_interface_id = (known after apply)
}
+ private_dns_name_options {
+ enable_resource_name_dns_a_record = (known after apply)
+ enable_resource_name_dns_aaaa_record = (known after apply)
+ hostname_type = (known after apply)
}
+ root_block_device {
+ delete_on_termination = (known after apply)
+ device_name = (known after apply)
+ encrypted = (known after apply)
+ iops = (known after apply)
+ kms_key_id = (known after apply)
+ tags = (known after apply)
+ throughput = (known after apply)
+ volume_id = (known after apply)
+ volume_size = (known after apply)
+ volume_type = (known after apply)
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ aws_instance_arn = (known after apply)
────────────────────────────────────────────────────────────────────────────
Saved the plan to: plan.tfplan
To perform exactly these actions, run the following command to apply:
terraform apply "plan.tfplan"
The CLI output shows AWS data sources being read before a `+ create` action for one `aws_instance`. Review both the proposed action and the resource it affects before applying. section 2.1.6
The graph determines action order from dependencies, not from the order of blocks in a file. For example, a subnet lookup that uses a VPC lookup’s ID must wait for the VPC lookup. Terraform can infer that relationship from the attribute reference. Because a DAG cannot contain circular dependencies, dependency problems can prevent a valid plan. section 2.2.5 section 1.7
Review a replacement before making it
If a resource needs rebuilding, run `terraform plan -replace 'RESOURCE_ADDRESS'` and inspect the whole result. Replacing one TLS private key in the example also destroys and recreates two dependent resources. Quote an indexed address so the shell does not misinterpret it. Prefer this reviewable plan to the deprecated `terraform taint` command, which changes state immediately. section 5.3.2
A plan cannot supply values that become known only after apply. In a Terraform test run with `command = plan`, an assertion against such an output fails with an unknown-condition error; test values available during planning instead, or use an apply run. section 9.4.1
For automation that needs structured plan data rather than CLI output alone, save a plan file and read it with `terraform show`. That representation includes changes, the prior state, and planned values; producing and processing it requires more than one command. section 11.1.8
