TFLAB27-terraform state Commands: Inspecting and Manipulating State

terraform state Commands: Inspecting and Manipulating State

🔧 Terraform Core ⭐ Intermediate state list state show state mv state rm state pull

Scenario

You need to rename a resource in your config without destroying and recreating it. You also want to remove a resource from Terraform's management (without deleting it from AWS), and inspect what's currently tracked in state. The terraform state family of commands gives you direct control over the state file.

Your Objectives
  • Use terraform state list to see all tracked resources.
  • Use terraform state show to inspect a resource's details.
  • Use terraform state mv to rename a resource in state (without destroy/recreate).
  • Use terraform state rm to remove a resource from state (without deleting it from AWS).
  • Use terraform state pull to download remote state.

Additional Context

state mv is the CLI-based rename. For a declarative approach, use moved blocks (Lab 29). Both achieve the same result — moving a resource to a new address in state without destroying it.

state rm removes a resource from Terraform's tracking WITHOUT deleting it from the cloud. The resource still exists in AWS; Terraform just stops managing it. This is useful when transferring ownership of a resource to another Terraform config or to manual management.

main.tf

terraform {
  required_version = ">= 1.5.0"
  required_providers {
    aws = { source = "hashicorp/aws", version = "~> 5.0" }
  }
}

provider "aws" { region = "us-east-1" }
data "aws_caller_identity" "current" {}

resource "aws_s3_bucket" "old_name" {
  bucket = "state-cmds-demo-${data.aws_caller_identity.current.account_id}"
  tags   = { ManagedBy = "terraform" }
}

resource "aws_s3_bucket" "unmanaged" {
  bucket = "soon-unmanaged-${data.aws_caller_identity.current.account_id}"
  tags   = { ManagedBy = "terraform" }
}

Workflow Commands

terraform init && terraform apply

# ─── state list: See everything Terraform tracks ───
terraform state list
# data.aws_caller_identity.current
# aws_s3_bucket.old_name
# aws_s3_bucket.unmanaged

# ─── state show: Inspect a specific resource ───
terraform state show aws_s3_bucket.old_name
# Shows all attributes: bucket, arn, region, tags, etc.

# ─── state mv: Rename in state (no destroy/recreate) ───
# Step 1: Rename the resource in main.tf: old_name → new_name
# Step 2: Move in state to match
terraform state mv aws_s3_bucket.old_name aws_s3_bucket.new_name
# Move "aws_s3_bucket.old_name" to "aws_s3_bucket.new_name"
# Successfully moved 1 object(s).

# Now terraform plan shows no changes (state matches config)
terraform plan   # "No changes."

# ─── state rm: Stop managing a resource (keep it in AWS) ───
terraform state rm aws_s3_bucket.unmanaged
# Removed aws_s3_bucket.unmanaged
# Successfully removed 1 resource instance(s).

# The bucket still exists in AWS, but Terraform no longer tracks it
terraform state list   # only shows aws_s3_bucket.new_name

# ─── state pull: Download remote state as JSON ───
terraform state pull > state-backup.json

terraform destroy
✓ state show Output
# aws_s3_bucket.old_name:
resource "aws_s3_bucket" "old_name" {
    arn                         = "arn:aws:s3:::state-cmds-demo-123456789012"
    bucket                      = "state-cmds-demo-123456789012"
    bucket_regional_domain_name = "state-cmds-demo-123456789012.s3.us-east-1.amazonaws.com"
    id                          = "state-cmds-demo-123456789012"
    region                      = "us-east-1"
    tags                        = { "ManagedBy" = "terraform" }
    tags_all                    = { "ManagedBy" = "terraform" }
}