
This post is part of a series on The Developer's Guide to HCL.
The terraform_data resource (Terraform v1.4+) is a versatile, built-in tool for managing arbitrary data, triggering actions, and orchestrating provisioners within the Terraform lifecycle, without creating external infrastructure. It functions as a generic data container or action trigger, available natively without provider installation, simplifying setup. Key uses include storing lifecycle-managed values, hosting provisioners when no other resource is suitable, and replacing the older null_resource. This guide explores its capabilities, best practices, and migration.
terraform_data vs. null_resource
As Terraform's built-in successor to the hashicorp/null provider's null_resource, terraform_data (v1.4+) offers key advantages: it requires no external provider, its triggers_replace argument supports all value types (unlike null_resource's string-only triggers), and it provides explicit input/output attributes for data handling. It is the recommended choice for new configurations.
terraform_data uses key arguments: input (optional) stores arbitrary data, causing an update if its value changes, and triggers_replace (optional) forces resource replacement if its value changes. Read-only attributes include output (reflecting input's value) and id (unique resource identifier). The choice between input and triggers_replace dictates whether downstream actions see an update or a full replacement.
Name
Type
Description
Behavior on Change
input
Argument
(Optional) Arbitrary data stored in state, reflected in output.
Plans an in-place update for terraform_data.
triggers_replace
Argument
(Optional) Arbitrary data whose change forces resource replacement.
Forces replacement of terraform_data.
output
Attribute
Value of the input argument.
Changes if input changes.
id
Attribute
Unique resource identifier.
N/A (assigned by Terraform)
terraform_data is useful for:
lifecycle.replace_triggered_by (e.g., redeploying services based on a version change).for_each for dynamic data handling or actions. While versatile for decoupling logic, avoid over-reliance to maintain clarity.The triggers_replace argument is central for advanced scenarios, forcing resource replacement when its computed value (any data type: string, list, map, filemd5(), timestamp()) changes from the previous state. This allows precise triggering based on diverse conditions. A common challenge involves boolean flags: triggers_replace reacts to a boolean's change (e.g., false to true or true to false), not its static true state. The idiomatic solution is often conditional resource creation using for_each (e.g., for_each = var.enable_feature ? toset(["active"]) : toset()).
terraform_data often hosts create and destroy provisioners when no other logical resource fits. Within provisioners, the self object provides access to input, output, and triggers_replace values, crucial for context-aware actions, especially stateful cleanup in destroy provisioners. However, provisioners are a last resort. Prefer native Terraform resources, data sources, cloud-init, or dedicated configuration management tools. Using provisioners means the user is responsible for script idempotency and any state managed outside Terraform.
Effective use of terraform_data involves:
terraform_data instance.terraform_data is a utility for ancillary tasks, and that management of any state altered by its provisioners falls to the user.Be aware of:
local-exec provisioners create dependencies on the execution environment's tools.triggers_replace behavior with boolean flags (reacts to change, not absolute value).input values can bloat the state file.null_resourceMigrating from null_resource to terraform_data (recommended for Terraform v1.4+) is streamlined using a moved block. This allows changing the resource type and renaming triggers to triggers_replace while preserving state history. After defining the terraform_data resource and the moved block, terraform plan should show no net changes, confirming a successful state migration path. The moved block can be removed after applying the changes.
terraform_data is a valuable built-in resource for managing arbitrary data, triggering actions, and replacing null_resource, enhancing IaC flexibility. It internalizes common patterns, making Terraform more self-sufficient. However, responsible use is crucial: prefer native solutions, ensure script idempotency and security, and maintain clarity. While terraform_data effectively addresses many needs, future Terraform versions may offer further refinements for complex triggering logic.

