Safeguard
Developer Tools•

Terraform ephemeral values and write-only arguments explained

Ephemeral values and write-only arguments keep secrets out of Terraform state and plan files. How each works, which versions, and where they stop.

Safeguard Security Team
3 min read

Ephemeral values exist only while Terraform runs and are omitted from state and plan files. Terraform 1.10 introduced ephemeral variables, outputs and resources. Terraform 1.11 added write-only arguments, which hand a temporary value to a managed resource without storing it. Together they let you stop persisting secrets.

The problem they solve

Before these features, any secret that reached a resource argument was written to state. Marking it sensitive only hid it on screen. The only real defence was protecting the state file, which means every reader of state could read every secret.

Ephemeral values change that for the values that opt in. The secret is used during the run, then dropped.

Three forms

HashiCorp's documentation describes three forms.

  • Ephemeral variables and child module outputs. You set the ephemeral argument. The value is available at runtime and left out of state and plans.
  • Ephemeral resources. An ephemeral block reads or opens something for the duration of the run, such as fetching a secret. Terraform does not store these in state or plan files. Providers define which ephemeral resources they offer.
  • Write-only arguments. Arguments on managed resources that accept a value but never persist it. They typically end in _wo and pair with a _wo_version argument.

How write-only updates work

Because Terraform stores nothing, it cannot compare the old and new value to see whether it changed. That is why the paired version argument exists. You increment _wo_version when you want the resource to receive a new value. If you change the secret but not the version, nothing happens.

This is a real operational difference. Rotation becomes an explicit change in code, which is also easy to review.

Where they can be used

Ephemeral values are limited to specific contexts, including locals, provider configuration, provisioners and write-only arguments. The ephemeral argument cannot be used on root module outputs. Anything you need after the run must be captured in another resource, since ephemeral values do not persist.

You can combine ephemeral with sensitive. The value is then omitted from state and redacted in the CLI and UI.

What they do not fix

  • Provider support. A resource only has a write-only argument if its provider added one. Check the provider documentation for the field you care about.
  • Existing secrets. Values already in state stay there until you migrate the resource and rotate the secret. Moving to a write-only argument does not scrub history, including versioned backend copies.
  • Where the secret comes from. If the value still lives in a variable file in Git, you have moved the problem. Pair ephemeral resources with a secrets manager.

A migration approach

  1. List the resources whose state holds credentials.
  2. Check each provider for a write-only or ephemeral option.
  3. Switch one resource, apply, and confirm the secret no longer appears in state.
  4. Rotate the secret, because the old value is in earlier state versions.
  5. Add a review rule: new credentials use ephemeral or write-only paths where available.

Quick check

Which Terraform versions introduced these features?

HashiCorp's documentation lists ephemeral values and resources at Terraform 1.10 and write-only arguments at 1.11. Confirm your own version before relying on them.

Does moving to a write-only argument remove old secrets from state?

No. It stops new persistence. Earlier state versions may still hold the old value, so rotate the secret after migrating.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.