Terraform State Commands
Learn the most important Terraform state and import commands, including terraform state list, show, mv, rm, import, and refresh-related workflows.
Why Terraform State Commands Exist
Most of the time, Terraform updates state automatically. You run terraform plan and terraform apply, and Terraform handles the internal bookkeeping for you.
But real infrastructure projects are messy. Resource names change. Modules get reorganized. Existing cloud resources need to be brought under Terraform management. Sometimes you need to inspect state directly to understand what Terraform thinks it owns.
That is where Terraform state commands come in.
These commands let you inspect or carefully adjust Terraform's record of managed infrastructure without always changing the actual cloud resources themselves.
This is powerful, but it also means you must use these commands with care. Many of them affect Terraform's memory of infrastructure, not the infrastructure itself.
When Should You Use State Commands?
State commands are most useful when you need to:
- inspect what Terraform currently manages
- examine the stored attributes of a resource
- rename or move resource addresses after refactoring code
- stop Terraform from managing a resource without deleting it
- import existing infrastructure into Terraform
- refresh Terraform's understanding of real infrastructure
For day-to-day Terraform usage, you may not need them often. But when you do need them, they are essential.
terraform state list
The terraform state list command shows all resource addresses currently tracked in state.
terraform state list
Example output:
aws_vpc.main
aws_subnet.public[0]
aws_subnet.public[1]
aws_internet_gateway.main
aws_security_group.web
aws_instance.web
module.network.aws_route_table.public
Why terraform state list is useful
This command answers the question: What does Terraform think it manages right now?
That is helpful when:
- debugging unexpected plans
- exploring a large module-based configuration
- preparing to move or remove a resource from state
- checking whether a resource was imported successfully
Practical example
Suppose you refactored code and Terraform says a resource will be destroyed and recreated. terraform state list can help you confirm the existing state address before using terraform state mv.
terraform state show
The terraform state show command prints the state details for a single resource.
terraform state show aws_instance.web
Example output might include:
# aws_instance.web:
resource "aws_instance" "web" {
ami = "ami-0abcdef1234567890"
arn = "arn:aws:ec2:us-east-1:123456789012:instance/i-0123456789abcdef0"
associate_public_ip_address = true
id = "i-0123456789abcdef0"
instance_type = "t3.micro"
private_ip = "10.0.1.24"
public_ip = "54.12.34.56"
}
Why terraform state show is useful
state show helps you inspect what Terraform currently knows about a resource.
Common uses:
- checking resource IDs
- verifying tag values
- confirming subnet associations
- seeing whether a provider attribute exists in state
- troubleshooting why Terraform wants to change something
Important note
This is state data, not necessarily a complete live API response from the provider at that exact second. It reflects Terraform's recorded or refreshed view.
terraform state mv
The terraform state mv command changes a resource's address in the state file.
It does not recreate the cloud resource. It tells Terraform, “This existing object should now be tracked under a different address.”
Basic syntax
terraform state mv aws_instance.web aws_instance.app
Common use case: renaming a resource
Imagine you rename this resource in code:
resource "aws_instance" "web" {
to:
resource "aws_instance" "app" {
If you do nothing, Terraform sees:
aws_instance.webis gone -> destroy itaws_instance.appis new -> create it
That is not what you want. It is the same real instance; only the logical Terraform name changed.
So you run:
terraform state mv aws_instance.web aws_instance.app
Now Terraform tracks the same real instance under the new address.
Another use case: moving into a module
Suppose a resource used to live in the root module:
aws_security_group.web
After refactoring, it now belongs inside a module:
module.network.aws_security_group.web
You can move the state address:
terraform state mv aws_security_group.web module.network.aws_security_group.web
This is extremely useful during code refactoring.
terraform state rm
The terraform state rm command removes a resource from Terraform state without destroying the actual infrastructure object.
Syntax
terraform state rm aws_instance.web
After this command:
- the EC2 instance still exists in AWS
- Terraform no longer tracks it in state
Why would you use this?
Common scenarios include:
- you want Terraform to stop managing a resource
- you need to detach an object before handing it to another system
- state is wrong and you plan to re-import the resource cleanly
- a resource was created manually and is better managed elsewhere
Important warning
state rm only changes Terraform's memory. It does not delete the real object.
That sounds safe, but it can cause confusion. If the configuration still contains the resource block, the next terraform plan may try to create a new resource because Terraform no longer sees the old one in state.
So use state rm intentionally and understand what the next plan will do.
terraform import
terraform import brings an existing real infrastructure object under Terraform management by associating it with a resource address in state.
This is crucial when resources already exist before Terraform is introduced.
Example
Suppose an S3 bucket already exists in AWS:
- bucket name:
company-audit-logs
You write the Terraform resource block first:
resource "aws_s3_bucket" "audit_logs" {
bucket = "company-audit-logs"
}
Then import it:
terraform import aws_s3_bucket.audit_logs company-audit-logs
Now Terraform tracks that bucket in state.
Why import matters
Many real environments are not built from scratch. They contain existing networks, buckets, IAM roles, or databases. Import lets Terraform adopt them gradually.
Important detail
Import adds the object to state, but you still need your configuration to match the real resource accurately. After importing, run terraform plan and expect to refine the .tf code until Terraform no longer shows unexpected changes.
terraform refresh
Historically, terraform refresh updated state to reflect the current real infrastructure without changing resources.
terraform refresh
What it does conceptually
Terraform queries the provider APIs, reads current infrastructure details, and updates the state accordingly.
Why it matters
This can help when you suspect drift or when you want Terraform's stored view to reflect the latest real-world information.
Modern caution
In modern Terraform workflows, many teams prefer terraform plan or terraform apply -refresh-only because they make refresh behavior more explicit and easier to review. But it is still important to understand the refresh concept because state must periodically be reconciled with reality.
Beginner takeaway
Think of refresh as: update Terraform's state to match what exists right now.
When to Use Each Command
Here is a practical summary.
| Command | Use it when... |
|---|---|
terraform state list | You want to see every resource Terraform currently tracks |
terraform state show | You want detailed stored attributes for one resource |
terraform state mv | You refactored resource addresses and need to keep the same real object |
terraform state rm | You want Terraform to forget a resource without deleting it |
terraform import | A real resource exists already and must be brought under Terraform management |
terraform refresh | You want state updated to reflect real infrastructure, or you want to understand refresh behavior |
Refactoring Example: Rename Without Recreate
Imagine this original resource:
resource "aws_security_group" "web" {
name = "web-sg"
}
Later, you realize app is a better name:
resource "aws_security_group" "app" {
name = "web-sg"
}
If you run terraform plan immediately, Terraform may want to destroy and recreate the security group. To preserve the existing object, you use:
terraform state mv aws_security_group.web aws_security_group.app
This tells Terraform the object already exists; only the address changed.
Reorganizing into Modules
State commands become even more valuable when you modularize Terraform.
Suppose a subnet resource used to live at:
aws_subnet.public[0]
After creating a child module, the new address becomes:
module.network.aws_subnet.public[0]
Instead of recreating the subnet, you move the state address:
terraform state mv aws_subnet.public[0] module.network.aws_subnet.public[0]
That preserves the actual infrastructure while aligning state with the new code structure.
Import Workflow Example
A realistic import workflow often looks like this:
- identify an existing resource in the cloud
- write a Terraform resource block for it
- run
terraform import - run
terraform plan - update the code until the plan is clean or intentionally understood
For example, importing an existing security group:
terraform import aws_security_group.web sg-0123456789abcdef0
After import, Terraform knows about the security group, but your code may still be incomplete. Maybe ingress rules or tags differ. The follow-up terraform plan reveals that gap.
Common Risks and Mistakes
Using state commands casually
State commands are not everyday formatting tools. They change Terraform's understanding of infrastructure. Always know why you are running one.
Forgetting to back up or rely on remote backend safeguards
State changes can be disruptive if done incorrectly. In production, versioned remote state and locking are valuable safety nets.
Running state rm but leaving the resource block in code
Terraform may then plan to recreate the resource because it still appears in configuration.
Importing without matching the configuration
Import only updates state. It does not automatically write perfect .tf code for you. Expect to reconcile the configuration afterward.
Assuming state show is a live API browser
It shows Terraform's current recorded information, not necessarily a complete real-time console replacement.
Best Practices for State Commands
- Use remote backends with versioning and locking in team environments.
- Run
terraform planbefore and after significant state operations. - Use
state mvduring refactors to avoid unnecessary recreation. - Use
state rmonly when you intentionally want Terraform to forget an object. - After imports, refine configuration until the plan is understood.
- Prefer reviewable refresh workflows in modern Terraform usage.
- Treat state operations as high-impact changes.
Final Thoughts
Terraform state commands are the advanced toolbox for managing Terraform's memory of infrastructure. They are not needed every day, but they become invaluable when you refactor code, adopt existing resources, or debug what Terraform thinks it owns.
A simple way to remember them is:
state listshows what Terraform tracksstate showshows what Terraform knows about one objectstate mvchanges where Terraform tracks itstate rmmakes Terraform forget itimporthelps Terraform adopt itrefreshhelps Terraform reconcile state with reality
Used carefully, these commands let you evolve Terraform code without unnecessary destruction and bring existing infrastructure under consistent management.
Knowledge Check
Question 1: state mv
When is terraform state mv most useful?
Question 2: state rm
What happens when you run terraform state rm aws_instance.web?
Question 3: import
What is the main purpose of terraform import?