Terraform Output Values with Examples

Tested on Ubuntu 26.04 LTS (Resolute Raccoon)
Package terraform 1.15.8-1
Applies to Any host with Terraform installed
Lab environment Single Ubuntu VM with Terraform — Terraform lab environment on Ubuntu
Privilege Normal user; sudo only if Terraform is not installed yet
Scope Terraform output blocks, resource attribute exports, description, sensitive, terraform output command, named output, -raw, -json, jq, complex values, outputs in state, shell automation, update and destroy behavior, and common output errors. Does not cover module output design, remote state consumption, HCP outputs, or secrets management depth.
Related guides Terraform variables
Terraform resources
Terraform state
terraform apply command
Terraform Associate certification course

After terraform apply creates infrastructure, you often need a value back: a hostname, an ID, or a generated string. An output block publishes that value from your configuration:

hcl
output "message" {
  value = terraform_data.example.output
}

The value expression can reference any resource attribute, local value, or input variable. Root-module outputs are what you read with the terraform output CLI command. Child modules use the same block syntax to expose values to their caller; module wiring is a separate topic.

NOTE
Work in ~/terraform-labs/terraform-output/ on the Terraform lab environment on Ubuntu. Run terraform init in each subdirectory before apply. Examples use the built-in terraform_data resource so you do not need cloud credentials.

Terraform output values and block syntax

An output is the outbound half of a module interface. Input variables flow in; outputs flow out. In a root module, outputs make selected values easy to query without opening Terraform state manually.

Argument Purpose
value Required expression Terraform evaluates and exports
type Optional type constraint for the output value
description Documents what the output contains and how consumers should use it
sensitive Redacts the value in normal plan/apply output
ephemeral Child modules only; omits the value from state and plan files
depends_on Rare explicit dependency when value cannot express it
deprecated Child modules only; warns module consumers to use another output
precondition Validates a condition before Terraform exposes/stores the output

ephemeral is available for child-module outputs only. It prevents the value from being written to state or plan files and restricts where that value can be consumed. Root-module outputs cannot be ephemeral.

A minimal block pairs a name with a value and optional description:

hcl
output "result" {
  description = "Short string for -raw automation demos"
  value       = "lab-ok"
}

Optional type constrains the output value. For full type-system rules, see Terraform data types:

hcl
output "result" {
  type        = string
  description = "Result returned to module consumers"
  value       = "lab-ok"
}

Write descriptions for humans and automation maintainers: what the value is, not just that it exists. Avoid description = "The result output."

depends_on inside an output block is uncommon. Terraform usually infers dependencies from the value expression. Reserve explicit depends_on for side-effect ordering that attribute references cannot capture.

precondition blocks validate an output before Terraform stores it, similar to variable validation. Full custom condition patterns live in the Terraform validation and check blocks lesson; outputs only need a short example here:

hcl
output "message" {
  value = terraform_data.example.output

  precondition {
    condition     = terraform_data.example.output != ""
    error_message = "message output must not be empty after apply."
  }
}

Expose resource attributes with apply

The main lab at ~/terraform-labs/terraform-output/main/ ties several outputs to one terraform_data resource:

hcl
terraform {
  required_version = ">= 1.12.0"
}

resource "terraform_data" "example" {
  input = "hello from terraform_data"
}

output "message" {
  description = "Echo of the terraform_data input after apply"
  value       = terraform_data.example.output
}

output "result" {
  description = "Short string for -raw automation demos"
  value       = "lab-ok"
}

output "tags" {
  description = "Map output for JSON demos"
  value = {
    env  = "lab"
    role = "demo"
  }
}

output "subnet_ids" {
  description = "List output for JSON demos"
  value       = ["subnet-a", "subnet-b"]
}

output "api_token" {
  description = "Sensitive credential placeholder"
  value       = "s3cr3t-token"
  sensitive   = true
}

Initialize the working directory:

bash
cd ~/terraform-labs/terraform-output/main && terraform init

Apply the configuration so Terraform creates the resource and records outputs in state:

bash
cd ~/terraform-labs/terraform-output/main && terraform apply -auto-approve -input=false

The apply footer lists every output. message echoes the resource result, api_token is redacted, and complex types print as HCL collections:

output
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

api_token = <sensitive>
message = "hello from terraform_data"
result = "lab-ok"
subnet_ids = [
  "subnet-a",
  "subnet-b",
]
tags = {
  "env" = "lab"
  "role" = "demo"
}

message reads terraform_data.example.output, so the output tracks the resource attribute rather than a hardcoded string.


Read outputs with the terraform output command

Once state contains outputs, the terraform output command reads them without another apply.

List every output in HCL format:

bash
cd ~/terraform-labs/terraform-output/main && terraform output
output
api_token = <sensitive>
message = "hello from terraform_data"
result = "lab-ok"
subnet_ids = [
  "subnet-a",
  "subnet-b",
]
tags = {
  "env" = "lab"
  "role" = "demo"
}

Request one output by name. Terraform prints the value in HCL syntax, so strings include quotes:

bash
cd ~/terraform-labs/terraform-output/main && terraform output result
output
"lab-ok"

For shell scripts, -raw strips quotes and formatting. It accepts only strings, numbers, and booleans:

bash
cd ~/terraform-labs/terraform-output/main && terraform output -raw result
output
lab-ok

That unquoted value is what you want in VALUE=$(terraform output -raw result).

Machine-readable output uses -json. With no output name, Terraform wraps each value in metadata:

bash
cd ~/terraform-labs/terraform-output/main && terraform output -json | jq .
output
{
  "api_token": {
    "sensitive": true,
    "type": "string",
    "value": "s3cr3t-token"
  },
  "message": {
    "sensitive": false,
    "type": "string",
    "value": "hello from terraform_data"
  },
  "result": {
    "sensitive": false,
    "type": "string",
    "value": "lab-ok"
  },
  "subnet_ids": {
    "sensitive": false,
    "type": [
      "tuple",
      [
        "string",
        "string"
      ]
    ],
    "value": [
      "subnet-a",
      "subnet-b"
    ]
  },
  "tags": {
    "sensitive": false,
    "type": [
      "object",
      {
        "env": "string",
        "role": "string"
      }
    ],
    "value": {
      "env": "lab",
      "role": "demo"
    }
  }
}

Query a single complex output by name. Terraform returns the value JSON directly, so jq paths are shorter:

bash
cd ~/terraform-labs/terraform-output/main && terraform output -json tags | jq -r '.env'
output
lab

For the full metadata envelope, parse the named key from terraform output -json without a trailing argument: jq -r '.tags.value.env'.


Sensitive and complex output values

Mark credentials and tokens sensitive = true so plan and apply summaries hide them:

hcl
output "api_token" {
  description = "Sensitive credential placeholder"
  value       = "s3cr3t-token"
  sensitive   = true
}

During apply, api_token = <sensitive> appears in the footer. The default terraform output listing also redacts that name.

When you request a sensitive output by name, Terraform 1.15.8 prints the real value:

bash
cd ~/terraform-labs/terraform-output/main && terraform output api_token
output
"s3cr3t-token"

The same value appears in JSON and raw form:

bash
cd ~/terraform-labs/terraform-output/main && terraform output -json api_token
output
"s3cr3t-token"

-raw strips quotes the same way as for non-sensitive strings:

bash
cd ~/terraform-labs/terraform-output/main && terraform output -raw api_token
output
s3cr3t-token
WARNING
sensitive = true hides values from casual plan and apply logs, not from state or from explicit terraform output queries. Anyone with state access or shell access to your workspace can read the value. For broader secret handling, see Terraform sensitive data.

-raw cannot export maps or lists. The raw-complex error lab shows the failure:

bash
cd ~/terraform-labs/terraform-output/errors/raw-complex && terraform output -raw tags
output
Error: Unsupported value for raw output

The -raw option only supports strings, numbers, and boolean values, but
output value "tags" is object.

Use the -json option for machine-readable representations of output values
that have complex types.

Use -json plus jq for maps, lists, and objects instead.


Outputs in state, after updates, and after destroy

Terraform writes output values into the state file at apply time. That persistence is what makes terraform output work on later runs without re-creating resources.

When the underlying resource changes, outputs that reference it update on the next apply. The update/ lab starts with input = "version-1":

bash
cd ~/terraform-labs/terraform-output/update && terraform apply -auto-approve -input=false

Read the stored output before you change the resource:

bash
cd ~/terraform-labs/terraform-output/update && terraform output message
output
"version-1"

Change the resource input to "version-2" in main.tf, apply again, and re-query:

bash
cd ~/terraform-labs/terraform-output/update && terraform output message
output
"version-2"

The output tracked the in-place resource update.

After terraform destroy removes all managed resources, outputs disappear from state. From main/:

bash
cd ~/terraform-labs/terraform-output/main && terraform destroy -auto-approve -input=false

Then query outputs:

bash
cd ~/terraform-labs/terraform-output/main && terraform output
output
Warning: No outputs found

The state file either has no outputs defined, or all the defined outputs are
empty. Please define an output in your configuration with the `output`
keyword and run `terraform refresh` for it to become available.

Re-run apply when you need outputs again.


Shell automation and output vs input

Capture a primitive string for a script without parsing HCL quotes:

bash
VALUE=$(cd ~/terraform-labs/terraform-output/main && terraform output -raw result) && echo "$VALUE"
output
lab-ok

Keep automation narrow: one -raw call per primitive value, check exit codes, and avoid logging sensitive output names in shared CI logs.

Compare the three value mechanisms at a glance:

Mechanism Direction Syntax Set from CLI
Variable Input var.name Yes (-var, tfvars, TF_VAR_*)
Local Internal local.name No
Output Export terraform output name No (read after apply)

Common Terraform output errors

Reproduce each failure in an isolated subdirectory under ~/terraform-labs/terraform-output/errors/.

Output name not found

After apply, requesting an undefined output name fails:

bash
cd ~/terraform-labs/terraform-output/errors/not-found && terraform output does_not_exist
output
Error: Output "does_not_exist" not found

The output variable requested could not be found in the state file. If you
recently added this to your configuration, be sure to run `terraform apply`,
since the state won't be updated with new output variables until that command
is run.

No state or no applied outputs

Before the first apply, state has nothing to read:

bash
cd ~/terraform-labs/terraform-output/errors/no-state && terraform output
output
Warning: No outputs found

Invalid resource reference in value

An output value must reference declared objects. validate catches a bad reference before apply:

bash
cd ~/terraform-labs/terraform-output/errors/bad-reference && terraform validate
output
Error: Reference to undeclared resource

  on main.tf line 4, in output "broken":
   4:   value = nonexistent_resource.foo.id

A managed resource "nonexistent_resource" "foo" has not been declared in the
root module.

Quick troubleshooting reference

Symptom Likely cause Fix
Output "name" not found Typo or output added after last apply Match the block label; run terraform apply
Warning: No outputs found No state yet or post-destroy Apply configuration first
Unsupported value for raw output -raw used on map/list/object Use terraform output -json and jq
Reference to undeclared resource value points at missing resource Fix the expression or add the resource
Sensitive value in automation logs Named terraform output reveals secrets Restrict state access; avoid echoing sensitive names

References


Summary

You declared output blocks that export resource attributes, static strings, collections, and sensitive values from a root module. After apply, Terraform prints those values in the command footer and stores them in state, which is why terraform output works on later runs without touching cloud APIs again.

The CLI offers three reading modes: plain terraform output for human inspection, -raw for primitive shell capture, and -json with jq for maps and lists. Sensitive outputs are redacted in apply summaries but still retrievable by name on Terraform 1.15.8, and they remain in state until you destroy the stack.

When a plan changes a referenced resource, re-apply updates the stored output. After destroy, outputs vanish from state and terraform output warns that nothing is available. Next, pair outputs with Terraform variables for inputs and Terraform locals for internal derived values, or continue to Terraform data types when output type constraints matter.

Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)