Skip to content

Support lifecycle.ignore_changes in module calls using self selectors#38184

Draft
LorDima wants to merge 2 commits intohashicorp:mainfrom
LorDima:module-lifecycle-ignore-changes
Draft

Support lifecycle.ignore_changes in module calls using self selectors#38184
LorDima wants to merge 2 commits intohashicorp:mainfrom
LorDima:module-lifecycle-ignore-changes

Conversation

@LorDima
Copy link
Copy Markdown

@LorDima LorDima commented Feb 15, 2026

Fixes #27360

Summary

This PR adds support for lifecycle { ignore_changes = ... } inside module blocks.

The module call’s ignore_changes rules are applied to managed resources created by that module call, using a self-based selector to reference resources inside the called module.

Why self?

Module calls can use count or for_each, which means a single module block can expand into multiple module instances. A module-call lifecycle rule therefore needs a way to either:

  • apply to all module instances, or
  • target one specific module instance.

The self keyword provides a compact and readable way to express both:

  • self.<type>.<name>.<attr> applies to all instances of the module call
  • self[<key>].<type>.<name>.<attr> filters to one instance when the module call is expanded via count/for_each

This avoids introducing a new addressing scheme and keeps the rule anchored to “resources inside this module call”.

User-visible behavior

Basic usage:

module "bucket" {
  source = "./modules/gcs"

  lifecycle {
    ignore_changes = [
      self.google_storage_bucket.bucket.labels
    ]
  }
}

This causes Terraform to ignore changes to the selected attribute(s) for matching resources inside the module.

When the module call uses count / for_each, you can optionally filter by module instance key:

module "bucket" {
  source   = "./modules/gcs"
  for_each = toset(["a", "b", "c"])

  lifecycle {
    ignore_changes = [
      self["b"].google_storage_bucket.bucket.labels
    ]
  }
}

If the module key/index is not specified, changes to all matching <type>.<name>.<attr> across all module instances are ignored.

module "bucket" {
  source   = "./modules/gcs"
  for_each = toset(["a", "b", "c"])

  lifecycle {
    ignore_changes = [
      self.google_storage_bucket.bucket.labels # All 3 buckets label changes will be ignored
    ]
  }
}

More granular attribute paths work as well:

module "bucket" {
  source   = "./modules/gcs"
  for_each = toset(["a", "b", "c"])

  labels = {
    my-key-1 = "my-value-1"
    my-key-2 = "my-value-2"
  }

  lifecycle {
    ignore_changes = [
      self["b"].google_storage_bucket.bucket.labels["my-key-1"]
    ]
  }
}

Notes

  • These rules affect managed resources only (resource blocks), consistent with existing ignore_changes semantics.

  • ignore_changes = all on a module call applies to all managed resources under that module call.

  • As with resource-level ignore_changes, rules are evaluated against the resource schema and ignore only the specified attribute paths.

Implementation details

  • Module-call lifecycle decoding is implemented in internal/configs via a dedicated module-call lifecycle schema (rather than reusing the resource lifecycle schema).

  • Module-call ignore rules are applied at resource instance evaluation time, so that module instance keys are available and self["key"] filtering works reliably for count/for_each.

  • The implementation merges module-call ignore rules into the resource instance’s existing ignore_changes behavior and reuses Terraform’s existing ignore_changes processing logic (rather than duplicating diff logic).

Tests

go test ./... succeed

Manual tests:

  • self.<type>.<name>.<attr> applies across all module instances
  • self["key"].<type>.<name>.<attr> filters a single for_each instance

@hashicorp-cla-app
Copy link
Copy Markdown

hashicorp-cla-app bot commented Feb 15, 2026

CLA assistant check
All committers have signed the CLA.

@LorDima LorDima force-pushed the module-lifecycle-ignore-changes branch from cac50eb to 7f8a220 Compare February 15, 2026 20:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A method to override configuration and meta arguments within a module

1 participant