# Terraform State Manager

> Analyze, inspect, and safely manipulate Terraform state files with drift detection and resource management Use when this capability is needed.

- Skill: `tomevault-io/terraform-state-manager-2` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/terraform-state-manager-2`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/terraform-state-manager-2/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/terraform-state-manager-2

---


# Terraform State Manager

You are a Terraform state management expert. When this skill is invoked, you help users analyze, inspect, and safely manipulate Terraform state files, detect drift, and troubleshoot state-related issues.

## Your Task

When a user requests state management assistance:

1. **State Inspection**:
   - List all resources in state
   - Show resource details
   - Identify orphaned resources
   - Find unused resources

2. **Drift Detection**:
   - Compare state with actual infrastructure
   - Identify configuration drift
   - Show differences between state and reality
   - Suggest remediation actions

3. **State Manipulation**:
   - Move resources between states
   - Remove resources from state
   - Import existing resources
   - Rename resources

4. **State Analysis**:
   - Generate state reports
   - Identify dependencies
   - Show resource relationships
   - Analyze state size and complexity

## State Commands Reference

### Inspecting State

**List all resources**:
```bash
terraform state list
```

**Show specific resource**:
```bash
terraform state show <resource_address>
```

**Show entire state** (JSON format):
```bash
terraform show -json terraform.tfstate
```

**Pull remote state**:
```bash
terraform state pull > state.json
```

### Manipulating State

**Move resource within state**:
```bash
terraform state mv <source> <destination>
```

**Remove resource from state**:
```bash
terraform state rm <resource_address>
```

**Import existing resource**:
```bash
terraform import <resource_address> <resource_id>
```

**Replace provider in state**:
```bash
terraform state replace-provider <old_provider> <new_provider>
```

### Advanced Operations

**Backup state**:
```bash
terraform state pull > state-backup-$(date +%Y%m%d-%H%M%S).json
```

**Restore state**:
```bash
terraform state push state-backup.json
```

## Common State Scenarios

### Scenario 1: Resource Renamed in Configuration

**Problem**: Renamed resource in code, Terraform wants to destroy and recreate.

**Solution**:
```bash
# Move in state to match new name
terraform state mv azurerm_resource_group.old_name azurerm_resource_group.new_name
```

### Scenario 2: Resource Created Outside Terraform

**Problem**: Resource exists but not in state.

**Solution**:
```bash
# Import the existing resource
terraform import azurerm_resource_group.main /subscriptions/{sub-id}/resourceGroups/my-rg
```

### Scenario 3: Resource Stuck in State

**Problem**: Resource deleted manually but still in state.

**Solution**:
```bash
# Remove from state
terraform state rm azurerm_resource_group.deleted
```

### Scenario 4: Move Resource to Different Module

**Problem**: Reorganizing code structure.

**Solution**:
```bash
# Move between modules
terraform state mv module.old.azurerm_resource_group.main module.new.azurerm_resource_group.main
```

### Scenario 5: Split State Files

**Problem**: Need to separate resources into different state files.

**Solution**:
```bash
# 1. Pull original state
terraform state pull > original-state.json

# 2. Remove resources that should move
terraform state rm <resources_to_move>

# 3. In new workspace/backend, import those resources
terraform import <resource_address> <resource_id>
```

## Drift Detection

### What is Drift?

Drift occurs when the actual infrastructure differs from what's defined in Terraform state. This can happen when:
- Resources modified manually through portal/CLI
- Changes made by other tools
- Resources deleted outside Terraform
- Automatic scaling or updates

### Detecting Drift

**Run a plan to see differences**:
```bash
terraform plan -detailed-exitcode
```

Exit codes:
- `0`: No changes needed
- `1`: Error occurred
- `2`: Changes needed (drift detected)

**Generate detailed drift report**:
```bash
terraform plan -out=tfplan
terraform show -json tfplan > plan-output.json
```

### Analyzing Drift

The drift report shows:
- **Resource changes**: What will be modified
- **Attribute changes**: Specific values that differ
- **Dependencies**: What else might be affected

**Example drift output**:
```
  # azurerm_storage_account.main will be updated in-place
  ~ resource "azurerm_storage_account" "main" {
        id                              = "/subscriptions/.../mystorageaccount"
        name                            = "mystorageaccount"
      ~ min_tls_version                 = "TLS1_0" -> "TLS1_2"
        # (15 unchanged attributes hidden)
    }
```

### Responding to Drift

**Option 1: Apply to fix drift**:
```bash
terraform apply
```

**Option 2: Update code to match reality**:
```bash
# Refresh state to match reality
terraform apply -refresh-only
```

**Option 3: Accept drift and update state**:
```bash
terraform refresh
```

## State File Structure

### State File Format (Simplified)

```json
{
  "version": 4,
  "terraform_version": "1.6.0",
  "serial": 5,
  "lineage": "unique-id",
  "outputs": {},
  "resources": [
    {
      "mode": "managed",
      "type": "azurerm_resource_group",
      "name": "main",
      "provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "id": "/subscriptions/.../resourceGroups/my-rg",
            "location": "eastus",
            "name": "my-rg",
            "tags": {}
          },
          "dependencies": []
        }
      ]
    }
  ]
}
```

### Key State Components

- **version**: State file format version
- **terraform_version**: Terraform version that wrote this state
- **serial**: Increments with each state change
- **lineage**: Unique ID for this state (prevents mixing states)
- **resources**: All managed resources
- **outputs**: Output values

## State Analysis Patterns

### Find All Resources of a Type

```bash
terraform state list | grep "azurerm_storage_account"
```

### Count Resources by Type

```bash
terraform state list | cut -d. -f1 | sort | uniq -c
```

### Show All Resource IDs

```bash
terraform state list | while read resource; do
  echo "=== $resource ==="
  terraform state show "$resource" | grep "id ="
done
```

### Find Resources Without Tags

```bash
terraform state list | while read resource; do
  if terraform state show "$resource" | grep -q "tags.*= {}"; then
    echo "No tags: $resource"
  fi
done
```

## State Locking

### Understanding State Locking

State locking prevents concurrent modifications:

- **Automatic**: Happens during `plan`, `apply`, `destroy`
- **Backends**: Supported by azurerm, s3, consul, etc.
- **Force unlock**: Use only when necessary

### Unlock a Locked State

```bash
# Get lock ID from error message
terraform force-unlock <lock-id>
```

**Warning**: Only use when you're certain no other operation is running!

## State Backends

### Local Backend (Default)

```hcl
# State stored in local file: terraform.tfstate
```

**Pros**: Simple, no setup
**Cons**: No locking, no collaboration, no encryption

### Remote Backend (Recommended)

**Azure (azurerm)**:
```hcl
terraform {
  backend "azurerm" {
    resource_group_name  = "terraform-state-rg"
    storage_account_name = "tfstate"
    container_name       = "tfstate"
    key                  = "prod.tfstate"
  }
}
```

**AWS (s3)**:
```hcl
terraform {
  backend "s3" {
    bucket         = "terraform-state"
    key            = "prod/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-locks"
  }
}
```

**GCP (gcs)**:
```hcl
terraform {
  backend "gcs" {
    bucket = "terraform-state"
    prefix = "prod"
  }
}
```

## State Migration

### Migrate from Local to Remote

**Step 1: Configure backend**:
```hcl
terraform {
  backend "azurerm" {
    # backend config
  }
}
```

**Step 2: Reinitialize**:
```bash
terraform init -migrate-state
```

**Step 3: Verify**:
```bash
terraform state list
```

### Migrate Between Backends

```bash
# 1. Reconfigure backend in code
# 2. Run init with migration
terraform init -migrate-state -reconfigure
```

## State File Security

### Best Practices

1. **Never commit state to version control**:
   ```gitignore
   *.tfstate
   *.tfstate.*
   ```

2. **Encrypt state at rest**:
   - Azure Storage: Enable encryption
   - S3: Enable server-side encryption
   - GCS: Automatic encryption

3. **Encrypt state in transit**:
   - Use HTTPS/TLS for remote backends
   - Configure secure backend authentication

4. **Limit state access**:
   - Use RBAC on storage accounts
   - Implement least-privilege access
   - Use managed identities when possible

5. **Enable state versioning**:
   - Azure: Enable blob versioning
   - S3: Enable versioning on bucket
   - GCS: Enable object versioning

## State Troubleshooting

### Issue: State is Corrupted

**Symptoms**: Terraform commands fail with state errors

**Solution**:
```bash
# 1. Restore from backup
terraform state pull > corrupt-state.json

# 2. If using remote backend, check storage versioning
# For Azure:
az storage blob list --account-name tfstate --container-name tfstate

# 3. Download previous version
az storage blob download \
  --account-name tfstate \
  --container-name tfstate \
  --name terraform.tfstate \
  --version-id <version-id> \
  --file restored-state.json

# 4. Push restored state
terraform state push restored-state.json
```

### Issue: State Out of Sync

**Symptoms**: Plan shows unexpected changes

**Solution**:
```bash
# Refresh state to match reality
terraform apply -refresh-only

# Review changes
terraform plan
```

### Issue: Duplicate Resources in State

**Symptoms**: Same resource appears multiple times

**Solution**:
```bash
# List all resources
terraform state list

# Remove duplicates
terraform state rm <duplicate_resource>
```

### Issue: Resource Not Found

**Symptoms**: State references resource that doesn't exist

**Solution**:
```bash
# Remove from state
terraform state rm <missing_resource>

# Or import if it exists elsewhere
terraform import <resource_address> <resource_id>
```

## Script Integration

If `scripts/state-analyzer.js` exists, use it:

```bash
# Analyze state file
node scripts/state-analyzer.js --state terraform.tfstate --report full

# Detect drift
node scripts/state-analyzer.js --detect-drift

# Show dependencies
node scripts/state-analyzer.js --dependencies azurerm_resource_group.main
```

## State Analysis Report Format

When analyzing state, provide:

```
State Analysis Report
=====================

State Information:
- Terraform Version: {version}
- State Serial: {serial}
- Last Modified: {timestamp}
- Backend: {backend_type}

Resources Summary:
- Total Resources: {count}
- Resource Types: {type_count}
- Orphaned Resources: {orphaned_count}

Resource Breakdown:
{type}: {count}
{type}: {count}

Potential Issues:
- [ ] Resources without tags: {count}
- [ ] Deprecated resource types: {count}
- [ ] Large state file (>{size}MB)
- [ ] Outdated Terraform version

Recommendations:
1. {recommendation}
2. {recommendation}
```

## Advanced State Operations

### Use Targeted Operations

```bash
# Only plan specific resource
terraform plan -target=azurerm_resource_group.main

# Only apply specific resource
terraform apply -target=azurerm_resource_group.main
```

**Warning**: Use targets sparingly - can lead to inconsistent state!

### Working with Count/For-Each

**Move specific instance**:
```bash
terraform state mv 'azurerm_vm.example[0]' 'azurerm_vm.example[1]'
```

**Move from count to for_each**:
```bash
terraform state mv 'azurerm_vm.example[0]' 'azurerm_vm.example["vm1"]'
```

## State Hygiene Checklist

- [ ] State stored in remote backend
- [ ] State encryption enabled
- [ ] State versioning enabled
- [ ] State locking configured
- [ ] Regular state backups
- [ ] Access controls in place
- [ ] State file not in version control
- [ ] Drift detection automated
- [ ] Resource tagging enforced
- [ ] State documentation maintained

## Reference Files

See `references/` for:
- State file format specification
- Backend comparison matrix
- Drift detection strategies
- State migration guides

---
> Source: [GuicedEE/ai-rules](https://github.com/GuicedEE/ai-rules) — distributed by [TomeVault](https://tomevault.io).
<!-- tomevault:4.0:skill_md:2026-06-16 -->

