Skip to main content
RunBook Academy

TerraformXIII · Variables, Outputs, and LocalsOutputs

Outputs: The Configuration Interface

Foundation⏱ ~12 min🧪 Lab requiredbashterraform

What you'll learn

  • Declare outputs with descriptive documentation
  • Use outputs to expose useful information to operators and consumers
  • Mark sensitive outputs correctly
  • Use structured output for machine consumption

Prerequisites

Verified against Terraform CLI 1.9.x · OpenTofu 1.7.x · HCL 2.0 · bpg/proxmox provider 0.66+ · hashicorp/local provider 2.5+ · hashicorp/null provider 3.2+ · hashicorp/random provider 3.6+ · hashicorp/http provider 3.4+ · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · 2026-08-12

Not yet marked complete on this device.

An output is the configurations return statement. It exposes information about the resources to operators (via terraform output) and to other configurations (via the terraform_remote_state data source). A well-designed output interface is the difference between a configuration that supports multi-environment use and one that requires a duplication per environment.

Declaring an output

output "instance_id" {
  value       = aws_instance.web.id
  description = "The EC2 instance ID of the web server."
}

The fields:

  • value — the expression to evaluate. Most outputs are references to attributes of resources.
  • description — human-readable documentation. Required in production.

What makes a good output

A good output:

  • Has a clear single purpose. One output, one value.
  • Has documentation. Every output has a description.
  • Is useful. The output is consumed by an operator or another configuration.
  • Has a stable name. Renaming an output breaks every consumer.
# Good: focused, documented
output "vpc_id" {
  value       = aws_vpc.main.id
  description = "The ID of the VPC."
}

output "public_subnet_ids" {
  value       = aws_subnet.public
  description = "The public subnets, keyed by availability zone."
}

# Less good: underexposed
output "data" {
  value = aws_vpc.main
}

# Less good: too clever
output "everything" {
  value = {
    vpc = aws_vpc.main
    subnets = aws_subnet.public
    security_groups = aws_security_group.web
  }
}

The “everything” output conflates purpose with payload. The consumer does not know which attribute to use. The values schema is not explicit.

Sensitive outputs

A sensitive = true output hides the value in CLI output:

output "database_password" {
  value       = aws_db_instance.primary.password
  description = "The database password."
  sensitive   = true
}

When sensitive = true is set:

  • The CLI output is (sensitive).
  • The state file has the value in plain text.
  • The plan output also hides the value.

As with sensitive variables, this is a UI affordance, not a security control. The value is in the state. The state is encrypted at rest by the backend. The course has a dedicated lesson on this (Part XVI).

Structured outputs

For complex values, structured outputs are useful:

output "network" {
  value = {
    vpc_id          = aws_vpc.main.id
    vpc_cidr        = aws_vpc.main.cidr_block
    public_subnets  = aws_subnet.public
    private_subnets = aws_subnet.private
  }
  description = "Network topology: VPC, subnets, and IDs."
}

The output is a JSON object. The consumer can access the attributes:

data "terraform_remote_state" "network" {
  backend = "s3"
  config = {
    bucket = "mycompany-terraform-state"
    key    = "network/terraform.tfstate"
  }
}

resource "aws_instance" "web" {
  ami = "ami-0e1bed4f"
  subnet_id = data.terraform_remote_state.network.outputs.network.public_subnets["a"].id
}

The structured output is the contract between the producer and the consumer. Renaming the output breaks every consumer.

Output for operators

The CLI uses outputs to communicate information to operators:

terraform output

The output:

instance_id = "i-0abc123def456789"
public_dns = "ec2-1-2-3-4.compute-1.amazonaws.com"

The operator can read the output without parsing the state.

# Output as JSON
terraform output -json

# A specific output
terraform output -raw database_endpoint

The -raw flag is useful for scripting. The output is the literal value, with no quotes.

Output for cross-stack consumption

The output is the contract between two configurations:

# In the network configuration
output "vpc_id" {
  value = aws_vpc.main.id
  description = "The ID of the VPC."
}
# In the compute configuration
data "terraform_remote_state" "network" {
  backend = "s3"
  config = {
    bucket = "mycompany-terraform-state"
    key    = "network/terraform.tfstate"
  }
}

resource "aws_instance" "web" {
  ami = "ami-0e1bed4f"
  subnet_id = data.terraform_remote_state.network.outputs.vpc_id
}

The contract is the output name. Renaming the output breaks the consumer. The course has a dedicated lesson on remote state (Part XIII).

What not to output

A few patterns that should be avoided:

Sensitive values. Use a secrets manager instead. The state is the wrong place for credentials.

Computed values that are not used. Outputs are not free. Each output is stored in state and computed on every apply.

Implementation details. The consumer does not need to know the AMI ID; the consumer needs to know the instance ID.

Large collections. A for_each over a hundred resources produces a large output. Consider exposing counts or summaries instead.

Outputs and state

The output is in the state. The state is the source of truth for the output. The output is computed during the apply.

# Refresh the output
terraform refresh

# Show the output
terraform output

The output is the value as of the last apply. The output is not dynamic; it does not query the provider.

What comes next

The next lesson is providers — the plugins that translate Terraforms resource operations into API calls against a specific platform.

Verification

Knowledge check · 7 questions

  1. Q1. What is the role of variables in Terraform?

  2. Q2. What is the role of locals?

  3. Q3. Variables should be sensitive when they contain secrets.

  4. Q4. What is the highest-priority source of variable values?

  5. Q5. Which of the following are valid variable types? (Select all that apply.)

  6. Q6. What is the role of validation in a variable?

  7. Q7. A team uses .tfvars files in Git for production. What is the risk?

Passing score: 75%. Answers are checked in this browser.