Annotations allow you to customize automatically generated diagrams by:
Create a terravision.yml file in your Terraform directory:
format: 0.1
title: My Production Architecture
connect:
aws_lambda_function.api:
- aws_rds_cluster.database: Database queries
disconnect:
aws_cloudwatch_log_group.logs:
- aws_lambda_function.api
Run TerraVision:
terravision draw --source ./terraform
# Annotations are automatically loaded from terravision.yml
format: 0.1 # Required: annotation format version
title: "Diagram Title" # Optional: main diagram heading
connect:
# Add new connections
disconnect:
# Remove connections
add:
# Add new resources
remove:
# Delete resources
update:
# Modify existing resources
Option 1: Auto-load (recommended)
terravision.ymlOption 2: Specify path
terravision draw --source ./terraform --annotate /path/to/annotations.yml
title: "Production Environment - US East"
Add new connections between resources.
Basic connection:
connect:
aws_lambda_function.api:
- aws_rds_cluster.database
Connection with label:
connect:
aws_lambda_function.api:
- aws_rds_cluster.database: "SQL queries"
- aws_s3_bucket.uploads: "Store files"
Multiple sources:
connect:
aws_lambda_function.api:
- aws_rds_cluster.database: "Read/Write"
aws_ecs_service.web:
- aws_rds_cluster.database: "Read only"
Remove existing connections.
Basic disconnect:
disconnect:
aws_cloudwatch_log_group.logs:
- aws_lambda_function.api
- aws_ecs_service.web
Using wildcards:
disconnect:
aws_cloudwatch*.logs: # Matches any CloudWatch log group
- aws_ecs_service.this
- aws_ecs_cluster.this
Add resources that don’t exist in Terraform (external systems, on-prem resources).
Basic add:
add:
aws_subnet.external_subnet:
cidr_block: "10.0.5.0/24"
availability_zone: "us-east-1a"
Add with connections:
add:
external_api.payment_gateway:
endpoint: "https://api.payment.com"
connect:
aws_lambda_function.checkout:
- external_api.payment_gateway: "Process payments"
Delete resources from the diagram.
Basic remove:
remove:
- aws_iam_role.task_execution_role
- aws_cloudwatch_log_group.debug_logs
Using wildcards:
remove:
- aws_iam_role.* # Remove all IAM roles
Modify attributes of existing resources.
Add edge labels:
update:
aws_ecs_service.web:
edge_labels:
- aws_rds_cluster.database: "Database queries"
- aws_elasticache_cluster.cache: "Session storage"
Custom resource label:
update:
aws_lambda_function.api:
label: "API Gateway Handler"
Update with wildcards:
update:
aws_cloudfront*:
edge_labels:
- aws_acm_certificate.this: "SSL Certificate"
format: 0.1
# Main diagram title
title: "E-Commerce Platform - Production"
# Add connections not apparent from Terraform
connect:
aws_lambda_function.order_processor:
- aws_rds_cluster.orders_db: "Insert orders"
- aws_sqs_queue.notifications: "Send notifications"
aws_ecs_service.web:
- aws_elasticache_cluster.sessions: "Session cache"
# Remove noisy connections
disconnect:
aws_cloudwatch_log_group.*:
- aws_lambda_function.*
- aws_ecs_service.*
# Add external systems
add:
external_api.payment_gateway:
provider: "Stripe"
endpoint: "https://api.stripe.com"
external_api.shipping_service:
provider: "FedEx"
endpoint: "https://api.fedex.com"
# Remove internal resources from diagram
remove:
- aws_iam_role.lambda_execution
- aws_iam_policy.cloudwatch_logs
# Add custom labels
update:
aws_lambda_function.order_processor:
label: "Order Processing Engine"
edge_labels:
- external_api.payment_gateway: "Process payment"
- external_api.shipping_service: "Create shipment"
aws_ecs_service.web:
label: "Web Application (3 tasks)"
edge_labels:
- aws_alb.main: "HTTP/HTTPS traffic"
aws_cloudfront_distribution.cdn:
edge_labels:
- aws_s3_bucket.static_assets: "Static content"
- aws_alb.main: "Dynamic content"
Use wildcards to match multiple resources:
| Pattern | Matches | Example |
|---|---|---|
aws_lambda* |
All Lambda functions | aws_lambda_function.api, aws_lambda_function.worker |
*.logs |
All resources ending with .logs | aws_cloudwatch_log_group.api_logs |
aws_ecs_* |
All ECS resources | aws_ecs_service.web, aws_ecs_cluster.main |
Examples:
# Disconnect all CloudWatch logs from all Lambda functions
disconnect:
aws_cloudwatch*.logs:
- aws_lambda*
# Add edge labels to all CloudFront distributions
update:
aws_cloudfront*:
edge_labels:
- aws_acm_certificate.this: "SSL Cert"
# Remove all IAM roles
remove:
- aws_iam_role.*
Resource names follow Terraform conventions:
<resource_type>.<resource_name>
Examples:
aws_lambda_function.apiaws_rds_cluster.databaseaws_s3_bucket.uploadsFind resource names:
# Export graph data to see all resource names
terravision graphdata --source ./terraform --outfile resources.json
# View the JSON file
cat resources.json | jq 'keys'
Begin with just a title and a few connections:
format: 0.1
title: "My Architecture"
connect:
aws_lambda_function.api:
- aws_rds_cluster.db: "Queries"
Wildcards are powerful but can have unintended effects. Test incrementally.
Always add labels to custom connections:
connect:
aws_lambda_function.api:
- aws_rds_cluster.db: "Read/Write queries" # Good
# - aws_rds_cluster.db # Less clear
When adding external resources, include descriptive attributes:
add:
external_api.payment:
provider: "Stripe"
endpoint: "https://api.stripe.com"
purpose: "Payment processing"
Keep annotation files in Git alongside Terraform code:
terraform/
├── main.tf
├── variables.tf
└── terravision.yml # Annotations
Add annotations gradually and regenerate diagrams to verify:
# After each change
terravision draw --source ./terraform --show
add:
on_prem.datacenter:
location: "Corporate HQ"
network: "10.0.0.0/8"
connect:
aws_vpn_gateway.main:
- on_prem.datacenter: "Site-to-Site VPN"
add:
external_api.auth0:
service: "Auth0"
purpose: "Authentication"
connect:
aws_lambda_function.auth:
- external_api.auth0: "Verify tokens"
# Remove noisy IAM and logging resources
remove:
- aws_iam_role.*
- aws_iam_policy.*
- aws_cloudwatch_log_group.*
# Remove internal connections
disconnect:
aws_security_group.*:
- aws_subnet.*
title: "Customer Portal - Production (us-east-1)"
update:
aws_ecs_service.web:
label: "Customer Portal (10 tasks)"
aws_rds_cluster.main:
label: "Customer Database (Multi-AZ)"
aws_elasticache_cluster.sessions:
label: "Session Store (Redis 6.x)"
terravision.yml or specified with --annotateterravision graphdata to see exact namesterravision draw --debug to see processing details# List all resources to verify patterns
terravision graphdata --source ./terraform --show_services