> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ignore changes

> Explains Terraform lifecycle ignore_changes to prevent reconciliation of externally managed resource attributes such as tags, avoiding noisy plans while still detecting drift.

In this lesson we examine Terraform's lifecycle meta-argument `ignore_changes` and how it controls drift handling between your configuration and real infrastructure.

Unlike `prevent_destroy`, `ignore_changes` does not block deletion. Unlike `create_before_destroy`, it does not change replacement ordering. Instead, `ignore_changes` tells Terraform to tolerate specific differences between the resource configuration and the actual infrastructure — effectively controlling which attribute drift Terraform should not reconcile.

Key behaviors

* `ignore_changes` causes Terraform to detect differences but deliberately avoid acting on them for the specified attributes.
* Terraform will still refresh state and show the differences; it just won’t include those attributes in planned changes.
* This is most useful when an attribute is managed outside Terraform (for example by Azure Policy or another automation tool) and you want to avoid continual, unnecessary diffs.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/9l60TCpe5-axPZIp/images/Terraform-On-Azure/Lifecycle-Meta-Arguments/ignore-changes/terraform-ignore-drift-manage-attributes.jpg?fit=max&auto=format&n=9l60TCpe5-axPZIp&q=85&s=727d1cfb0d7251de9614150eb9b8f60f" alt="The image describes two functions of a Terraform feature: ignoring drift on certain attributes and managing attributes outside Terraform." width="1920" height="1080" data-path="images/Terraform-On-Azure/Lifecycle-Meta-Arguments/ignore-changes/terraform-ignore-drift-manage-attributes.jpg" />
</Frame>

When to use `ignore_changes`

A common scenario is platform-level governance applying tags or other properties to resources. For example, Azure Policy may automatically apply or mutate tags. If Terraform also declares tags in the configuration, Terraform will detect those policy-applied tags as drift and will attempt to reconcile them back to the configuration, causing constant diffs and noisy plans. Using `ignore_changes` for the `tags` attribute prevents Terraform from trying to overwrite values that are intentionally controlled by an external system.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/9l60TCpe5-axPZIp/images/Terraform-On-Azure/Lifecycle-Meta-Arguments/ignore-changes/azure-policy-terraform-tagging-illustration.jpg?fit=max&auto=format&n=9l60TCpe5-axPZIp&q=85&s=c1334b669446f72218bb70a3219bde76" alt="The image illustrates a scenario about ensuring that an Azure Policy for automatically tagging resources isn't overridden by Terraform, accompanied by the logos for Azure and Terraform." width="1920" height="1080" data-path="images/Terraform-On-Azure/Lifecycle-Meta-Arguments/ignore-changes/azure-policy-terraform-tagging-illustration.jpg" />
</Frame>

Example — storage account

1. Without `ignore_changes`

This resource config declares tags in Terraform. If Azure Policy or another process applies different tags, Terraform will plan an in-place update to match the configuration:

```hcl theme={null}
resource "azurerm_storage_account" "example" {
  name                     = var.storage_account_name
  location                 = "East US"
  resource_group_name      = "rg-workshop-riskaria"
  account_tier             = "Standard"
  account_replication_type = "LRS"
  public_network_access_enabled = true

  tags = {
    "Added from" = "Terraform"
  }
}
```

Example abbreviated plan output showing a tags diff:

```bash theme={null}
# terraform plan (example)
azurerm_storage_account.example: Refreshing state...
  ~ resource "azurerm_storage_account" "example" {
      ~ tags = {
          - "environment" = "policy-applied" -> null
          + "Added from"  = "Terraform"
        }
    }

Plan: 0 to add, 1 to change, 0 to destroy.
```

2. With `ignore_changes` for `tags`

Add a `lifecycle` block that instructs Terraform to ignore changes to the `tags` attribute:

```hcl theme={null}
resource "azurerm_storage_account" "example" {
  name                     = var.storage_account_name
  location                 = "East US"
  resource_group_name      = "rg-workshop-riskaria"
  account_tier             = "Standard"
  account_replication_type = "LRS"
  public_network_access_enabled = true

  tags = {
    "Added from" = "Terraform"
  }

  lifecycle {
    ignore_changes = [
      tags,
    ]
  }
}
```

After adding this lifecycle block, Terraform will still refresh and detect the external tags, but it will not plan any changes to reconcile them.

Example outputs

Terraform apply reporting no changes:

```bash theme={null}
$ terraform apply -var "storage_account_name=saqeworkshop0689" -auto-approve
Acquiring state lock. This may take a few moments...
azurerm_storage_account.example: Refreshing state...
[id=/subscriptions/25d172e2-1262-4980-8164-1d2c95eae1ff/resourceGroups/rg-qe-workshop-riskaria/providers/Microsoft.Storage/storageAccounts/saqeworkshop0689]
No changes. Your infrastructure matches the configuration.
Releasing state lock. This may take a few moments...
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
```

Querying the storage account tags with Azure CLI shows tags are controlled externally and not overwritten by Terraform:

```bash theme={null}
$ az storage account show -g rg-qe-workshop-riskaria -n saqeworkshop0689 --query tags
{}
```

Working in your editor / VS Code

* Reuse an existing storage account if convenient.
* Confirm the account exists using `az storage account list -o table`.
* If Terraform initially plans to change `tags`, add the `lifecycle { ignore_changes = [tags] }` block and re-run `terraform plan`. After adding `ignore_changes`, Terraform should no longer propose updates for that attribute.

Concise HCL example:

```hcl theme={null}
resource "azurerm_resource_group" "rg" {
  name     = "lifecycle-resources"
  location = "West Europe"
}

resource "azurerm_storage_account" "storage" {
  name                     = "lifecyclestorage75636"
  resource_group_name      = azurerm_resource_group.rg.name
  location                 = azurerm_resource_group.rg.location
  account_tier             = "Standard"
  account_replication_type = "LRS"

  tags = {
    environment = "lifecycle"
  }

  lifecycle {
    ignore_changes = [
      tags,
    ]
  }
}
```

Typical `terraform plan` outputs you may observe

* Before adding `ignore_changes`:

```bash theme={null}
# terraform plan (before ignore_changes)
azurerm_storage_account.storage: Refreshing state...
  ~ resource "azurerm_storage_account" "storage" {
      ~ tags = {
          - "environment" = "policy-managed" -> null
          + "environment" = "lifecycle"
        }
    }

Plan: 0 to add, 1 to change, 0 to destroy.
```

* After adding `ignore_changes`:

```bash theme={null}
# terraform plan (after ignore_changes)
azurerm_storage_account.storage: Refreshing state...

No changes. Your infrastructure matches the configuration.
```

Best practices and caveats

<Callout icon="lightbulb" color="#1CB2FE">
  Use `ignore_changes` sparingly and only for attributes that are legitimately owned by an external system (for example, tags applied by Azure Policy). Limit its scope to the minimal set of attributes you need to ignore to avoid hiding unexpected drift.
</Callout>

<Callout icon="warning" color="#FF6B6B">
  Do not overuse `ignore_changes` to mask configuration problems. Ignoring attributes makes Terraform blind to changes in those attributes and can make debugging and auditing more difficult. Always prefer centralizing ownership (for example using a policy-first tagging approach) where practical.
</Callout>

Quick comparison of lifecycle meta-arguments

| Meta-argument           | Purpose                                                                | Typical use case                                                         |
| ----------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `ignore_changes`        | Instruct Terraform to not act on differences for specified attributes  | Let platform or external tooling manage tags or properties               |
| `prevent_destroy`       | Prevent a resource from being destroyed by Terraform                   | Protect critical resources from accidental deletion                      |
| `create_before_destroy` | Ensure replacement resource is created before the old one is destroyed | Perform in-place replacements that require no downtime (where supported) |

Summary

* `ignore_changes` is useful to avoid reconciliation for attributes managed outside Terraform (e.g., tags applied by Azure Policy).
* Apply it narrowly — to the minimal set of attributes you explicitly want Terraform to ignore.
* Terraform will continue to detect differences but will not include the ignored attributes in the plan, preventing constant update churn.

Links and references

* [Terraform lifecycle meta-arguments — ignore\_changes](https://developer.hashicorp.com/terraform/language/meta-arguments/lifecycle#ignore_changes)
* [Azure Policy documentation](https://learn.microsoft.com/azure/governance/policy/)
* [Azure CLI: storage account list](https://learn.microsoft.com/cli/azure/storage/account?view=azure-cli-latest#az_storage_account_list)

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/terraform-on-azure/module/82cd6352-f026-4f6f-b739-634e56558de4/lesson/956f5453-cd68-4b1e-953d-8b4080929dc2" />

  <Card title="Practice Lab" icon="flask-conical" cta="Learn more" href="https://learn.kodekloud.com/user/courses/terraform-on-azure/module/82cd6352-f026-4f6f-b739-634e56558de4/lesson/cec76ae3-cbb9-4f33-8c55-c65cc5e0adfc" />
</CardGroup>
