terraform plan
Master terraform plan, understand execution plan output symbols (+/-/~/+/-), save plan files, target specific resources, detect configuration drift, and use plan in CI/CD pipelines.
What Is terraform plan?
terraform plan is the safety net of Terraform. Before making any infrastructure changes, it calculates exactly what would happen and shows you a precise diff, without actually doing anything.
terraform plan
Think of it as asking Terraform: "If I run apply right now, what changes will happen?" The answer is printed as an execution plan: a line-by-line breakdown of every resource that will be created, updated, replaced, or deleted.
Running plan is always safe. It has zero side effects. No API calls are made to create or destroy resources. You can run it as many times as you like.
Reading the Execution Plan
The plan output uses symbols to communicate each action:
| Symbol | Meaning | Risk |
|---|---|---|
+ | Resource will be created | New infrastructure |
- | Resource will be destroyed | Permanent deletion |
~ | Resource will be updated in-place | Change without recreation |
-/+ | Resource will be destroyed then recreated | Downtime risk! |
<= | Data source will be read | No infrastructure change |
Example Plan Output
Terraform will perform the following actions:
# aws_instance.web will be created
+ resource "aws_instance" "web" {
+ ami = "ami-0c55b159cbfafe1f0"
+ instance_type = "t3.micro"
+ id = (known after apply)
+ public_ip = (known after apply)
+ vpc_security_group_ids = (known after apply)
}
# aws_s3_bucket.assets will be updated in-place
~ resource "aws_s3_bucket" "assets" {
~ tags = {
+ "Environment" = "production"
"Name" = "my-assets"
}
}
# aws_instance.old will be destroyed
- resource "aws_instance" "old" {
- ami = "ami-0abcdef1234567890" -> null
- instance_type = "t2.micro" -> null
- id = "i-0abc12345def67890" -> null
}
Plan: 1 to add, 1 to change, 1 to destroy.
The final line is the summary. Read it every time before approving.
The -/+ Symbol, The Most Dangerous One
The -/+ symbol (destroy then create) is the one to pay careful attention to:
# aws_instance.web must be replaced
-/+ resource "aws_instance" "web" {
~ id = "i-0abc123" -> (known after apply) # forces replacement
~ ami = "ami-0old" -> "ami-0new" # forces replacement
}
Some resource attributes, like ami on an EC2 instance, cannot be changed in-place. Changing them forces Terraform to delete the old resource and create a new one. This means downtime.
Rule: Whenever you see
-/+in your plan, pause and think about the impact. Can your application handle a restart? Is there a safer way to do this migration?
Saving a Plan File with -out
You can save the execution plan to a file:
terraform plan -out=tfplan
This is the recommended practice for production deployments. When you later run terraform apply tfplan, Terraform applies exactly what was planned, nothing more, nothing less. No interactive approval prompt is shown.
This is the standard CI/CD pattern:
- CI pipeline runs
terraform plan -out=tfplanand posts the output for review - A human reviews and approves the plan
- CI pipeline runs
terraform apply tfplan, guaranteed to match what was reviewed
# In CI/CD
terraform plan -input=false -out=tfplan
terraform apply -input=false tfplan
The plan file is binary. Do not commit it to Git, it may contain secrets. In CI/CD, pass it between pipeline stages as an artifact.
Targeting Specific Resources with -target
The -target flag limits the plan to only the specified resource (and its dependencies):
# Plan only the S3 bucket
terraform plan -target=aws_s3_bucket.assets
# Plan only a specific module
terraform plan -target=module.vpc
-target is useful for debugging or making emergency changes to a single resource without touching the rest of the infrastructure.
Warning: Avoid
-targetin routine operations. It can leave your state out of sync with reality. Use it only for emergencies or debugging.
Detecting Drift
Drift happens when someone manually changes infrastructure (e.g., via the AWS console) without updating the Terraform config. When you run plan, Terraform compares your configuration against the real infrastructure (via the state file) and shows the drift:
# aws_security_group.web has been modified manually
~ resource "aws_security_group" "web" {
~ ingress = [
+ {
+ cidr_blocks = ["203.0.113.5/32"]
+ from_port = 22
+ to_port = 22
+ protocol = "tcp"
},
]
}
Plan: 0 to add, 1 to change, 0 to destroy.
This plan shows that someone opened port 22 manually. Running apply will remove that manual change and bring infrastructure back to the declared state. This is exactly the value of IaC, configuration is the source of truth.
terraform plan in CI/CD Pipelines
In automated pipelines, use these flags:
terraform plan \
-input=false \ # Prevent interactive prompts
-no-color \ # Disable ANSI colors for cleaner logs
-out=tfplan # Save plan for later apply
A minimal GitLab CI example:
plan:
stage: plan
script:
- terraform init -input=false
- terraform plan -input=false -no-color -out=tfplan
artifacts:
paths:
- tfplan
Common plan Errors
Error: No configuration files
Error: No configuration files
│ Plan requires configuration to be present.
You are running plan in the wrong directory. cd to the directory containing your .tf files.
Error: Invalid reference
Error: Reference to undeclared resource
│ on main.tf line 14
│ A managed resource "aws_vpc" "main" has not been declared.
You referenced a resource (aws_vpc.main) that does not exist in your config. Check your resource names.
Knowledge Check
Question 1: Plan Symbols
You run terraform plan and see this in the output: "-/+ resource aws_instance.web (forces replacement)". What does this mean?
Question 2: terraform plan -out
Your team uses terraform plan -out=tfplan in CI, then terraform apply tfplan in a separate stage. Why is this the recommended production pattern?
Question 3: Drift Detection
A colleague manually added an ingress rule to a security group in the AWS console. You run terraform plan. What will happen?