Skip to main content

Output Values

Output values are like return values for Terraform modules. They expose information about your infrastructure for use by other configurations, display to users, or integration with external tools.

Declaring Outputs

Declare output values using output blocks:
output "<NAME>" {
  value = <EXPRESSION>
}

Basic Example

output "instance_ip" {
  value       = aws_instance.web.public_ip
  description = "Public IP address of the web server"
}

Output Arguments

value
any
required
The value to export. Can be any Terraform expression.
value = aws_instance.web.id
value = [for i in aws_instance.web : i.private_ip]
value = {
  id = aws_instance.web.id
  ip = aws_instance.web.public_ip
}
description
string
Human-readable description of the output’s purpose.
description = "The public IP address of the web server"
sensitive
boolean
Hide the value in Terraform output. Default is false.
sensitive = true
depends_on
list
Explicit dependencies for the output.
depends_on = [
  aws_instance.web,
  aws_security_group.web,
]
ephemeral
boolean
Marks the output as ephemeral (not persisted in state).
ephemeral = true

Output Examples

Simple Values

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

output "public_ip" {
  value = aws_instance.web.public_ip
}

Complex Values

output "instance_details" {
  value = {
    id         = aws_instance.web.id
    public_ip  = aws_instance.web.public_ip
    private_ip = aws_instance.web.private_ip
    az         = aws_instance.web.availability_zone
  }
  description = "Complete details of the instance"
}

Collection Outputs

output "all_instance_ips" {
  value       = aws_instance.web[*].private_ip
  description = "Private IP addresses of all instances"
}

output "instance_map" {
  value = {
    for instance in aws_instance.web :
    instance.id => instance.private_ip
  }
}

Computed Outputs

output "connection_string" {
  value       = "https://${aws_instance.web.public_ip}:8080"
  description = "Complete connection string"
}

output "uppercase_name" {
  value = upper(var.instance_name)
}

Viewing Outputs

During Apply

Outputs are shown after terraform apply:
terraform apply

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

Outputs:

instance_id = "i-1234567890abcdef0"
public_ip = "54.123.45.67"

Query Outputs

View outputs without applying changes:
# All outputs
terraform output

# Specific output
terraform output instance_ip

# JSON format
terraform output -json

Output Format

# Raw value (useful for scripts)
terraform output -raw instance_ip

Sensitive Outputs

Mark outputs containing secrets:
output "database_password" {
  value     = aws_db_instance.database.password
  sensitive = true
}
Sensitive outputs:
  • Are hidden in terraform apply output
  • Show <sensitive> instead of the value
  • Can be viewed with terraform output
terraform output database_password
Sensitive outputs are still stored in plain text in the state file. Always encrypt your state file.

Module Outputs

Outputs are essential for module composition:

Child Module

# modules/web-app/outputs.tf
output "instance_id" {
  value       = aws_instance.app.id
  description = "ID of the application instance"
}

output "endpoint" {
  value = "https://${aws_instance.app.public_ip}"
}

Root Module

# main.tf
module "web_app" {
  source = "./modules/web-app"
  
  instance_type = var.instance_type
}

output "web_app_id" {
  value = module.web_app.instance_id
}

output "web_app_url" {
  value = module.web_app.endpoint
}

Preconditions

Validate output values:
output "api_endpoint" {
  value = aws_instance.api.public_ip
  
  precondition {
    condition     = aws_instance.api.public_ip != ""
    error_message = "API instance must have a public IP address."
  }
}
From internal/configs/named_values.go:443-461, outputs support preconditions but not postconditions.

Deprecated Outputs

Mark outputs as deprecated:
output "old_endpoint" {
  value      = aws_instance.web.public_dns
  deprecated = "Use 'endpoint' output instead"
}

Output Use Cases

Displaying Information

Show important information to users:
output "next_steps" {
  value = <<-EOT
    Your infrastructure is ready!
    
    SSH Command: ssh ubuntu@${aws_instance.web.public_ip}
    Web URL: http://${aws_instance.web.public_ip}
  EOT
}

Chaining Modules

Pass data between modules:
module "network" {
  source = "./modules/network"
}

module "compute" {
  source = "./modules/compute"
  
  vpc_id    = module.network.vpc_id
  subnet_id = module.network.subnet_id
}

Integration with Tools

Export data for external tools:
# Use in scripts
INSTANCE_IP=$(terraform output -raw instance_ip)
ssh ubuntu@$INSTANCE_IP

# Export to environment
export DB_HOST=$(terraform output -raw database_endpoint)

Remote State Data Source

Share outputs across configurations:
# Configuration A outputs
output "vpc_id" {
  value = aws_vpc.main.id
}

# Configuration B reads outputs
data "terraform_remote_state" "network" {
  backend = "s3"
  
  config = {
    bucket = "terraform-state"
    key    = "network/terraform.tfstate"
    region = "us-west-2"
  }
}

resource "aws_instance" "web" {
  vpc_id = data.terraform_remote_state.network.outputs.vpc_id
}

Output Examples from Source

From internal/configs/testdata/valid-files/outputs.tf:
output "foo" {
  value = "hello"
}

output "bar" {
  value = local.bar
}

output "baz" {
  value     = "ssshhhhhhh"
  sensitive = true
}

output "cheeze_pizza" {
  description = "Nothing special"
  value       = "🍕"
}

output "π" {
  value = 3.14159265359
  depends_on = [
    pizza.cheese,
  ]
}

Output Naming

Output names must:
  • Start with a letter or underscore
  • Contain only letters, digits, underscores, and hyphens
  • Be unique within the configuration
output "instance_id" { }      # Valid
output "instance-id" { }      # Valid
output "_private_data" { }    # Valid
output "2nd_instance" { }     # Invalid

Implementation Details

From internal/configs/named_values.go:362-381:
type Output struct {
    Name        string
    Description string
    Expr        hcl.Expression
    DependsOn   []hcl.Traversal
    Sensitive   bool
    Ephemeral   bool
    Deprecated  string
    
    Preconditions []*CheckRule
    
    DescriptionSet bool
    SensitiveSet   bool
    EphemeralSet   bool
    DeprecatedSet  bool
    
    DeclRange       hcl.Range
    DeprecatedRange hcl.Range
}

Best Practices

Add Descriptions

Always include descriptions to help users understand output purpose and usage.

Use Sensitive Flag

Mark outputs containing credentials or secrets as sensitive.

Structured Data

Group related values into objects for better organization.

Meaningful Names

Use clear, descriptive names that indicate the output’s content.

Common Patterns

Connection Information

output "connection_info" {
  value = {
    host     = aws_instance.web.public_ip
    port     = 22
    username = "ubuntu"
  }
  description = "SSH connection information"
}

Resource IDs

output "resource_ids" {
  value = {
    vpc        = aws_vpc.main.id
    subnet     = aws_subnet.public.id
    instance   = aws_instance.web.id
    security_group = aws_security_group.web.id
  }
}

Conditional Outputs

output "public_endpoint" {
  value = var.create_public_ip ? aws_instance.web.public_ip : null
}

Filtered Lists

output "production_instances" {
  value = [
    for instance in aws_instance.web :
    instance.id if instance.tags["Environment"] == "production"
  ]
}

Troubleshooting

Output Not Shown

If outputs don’t appear:
  1. Ensure the output block is valid
  2. Check that resources exist in state
  3. Verify expressions are correct

Sensitive Output Warning

Warning: Output "password" contains sensitive data
This is expected for sensitive outputs. Use -raw to view:
terraform output -raw password

Next Steps

Variables

Learn about input variables

Modules

Use outputs for module composition

Build docs developers (and LLMs) love