TrademarkTrademark
Features
Documentation
All articles

A Concise Guide to terraform_data Resource

Learn how terraform_data stores JSON, passes values between modules, and streamlines complex workflows with step-by-step examples and best practices.
Sebastian StadilAugust 7, 2025Updated March 31, 2026
A Concise Guide to terraform_data Resource

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.

Understanding Arguments and Attributes

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)

Key Use Cases

terraform_data is useful for:

  • Storing and referencing lifecycle-managed arbitrary data (e.g., consolidating configuration details).
  • Simulating resource dependencies or creating explicit data flows.
  • Triggering replacement of other resources via lifecycle.replace_triggered_by (e.g., redeploying services based on a version change).
  • Performing conditional checks or actions using provisioners (e.g., verifying external resource states), noting that provisioner-managed resources are outside Terraform state.
  • Creating multiple instances with for_each for dynamic data handling or actions. While versatile for decoupling logic, avoid over-reliance to maintain clarity.

Advanced Triggering and Dependency Management

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()).

Working with Provisioners

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.

Best Practices and Considerations

Effective use of terraform_data involves:

  • Prioritizing native Terraform resources/data sources over provisioners.
  • Ensuring provisioner scripts are idempotent and handle errors robustly.
  • Keeping logic focused and clear within each terraform_data instance.
  • Securing provisioners by avoiding hardcoded credentials and sanitizing inputs.
  • Understanding that terraform_data is a utility for ancillary tasks, and that management of any state altered by its provisioners falls to the user.

Limitations and Common Pitfalls

Be aware of:

  • Resources altered by provisioners are not tracked in Terraform state, potentially creating "shadow infrastructure."
  • local-exec provisioners create dependencies on the execution environment's tools.
  • Overuse can lead to complex, opaque configurations.
  • Misunderstanding triggers_replace behavior with boolean flags (reacts to change, not absolute value).
  • Large input values can bloat the state file.

Migrating from null_resource

Migrating 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.

Conclusion and Outlook

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.

Code editor displaying syntax-highlighted code on a dark screen

About the author
Sebastian StadilCEO at Scalr
Sebastian Stadil is the CEO at Scalr. He has over 15 years of devops experience, and started his career with AWS in 2004. Sebastian was also an early advisor to Microsoft Azure and Google Cloud.