TerraVision can draw a professional cloud architecture diagram from a plain JSON file, with no Terraform code and no cloud credentials. This is the fastest way for a person or an AI agent to get a diagram that uses the official AWS, Azure and GCP icon sets and industry-standard grouping (VPCs, subnets, resource groups, regions, zones).
Schema: https://patrickchugh.github.io/terravision/schemas/terravision-graph-1.0.schema.json
A TVG file is a JSON object. Each key is a node address, <type>.<name>, where <type> is a Terraform resource type such as aws_lambda_function, azurerm_key_vault or google_cloud_run_service, and <name> is any label you like. Each value is the list of node addresses that node connects to or contains. That is the whole format.
{
"tv_aws_users.users": ["aws_cloudfront_distribution.cdn"],
"aws_cloudfront_distribution.cdn": ["aws_s3_bucket.static_site", "aws_alb.api"],
"aws_vpc.main": ["aws_subnet.public~1", "aws_subnet.private~1"],
"aws_subnet.public~1": ["aws_alb.api"],
"aws_subnet.private~1": ["aws_lambda_function.orders"],
"aws_alb.api": ["aws_lambda_function.orders"],
"aws_lambda_function.orders": ["aws_dynamodb_table.orders", "aws_sqs_queue.events"]
}Render it:
terravision draw --source architecture.tvg.json --format svg # also png, pdf, dot, drawio
terravision draw --source architecture.tvg.json --title "Order Platform - Production"Only Graphviz and Git are required for this mode, the same minimum as every TerraVision command. Terraform is not invoked and does not need to be installed.
Save TVG files with the .tvg.json extension, for example architecture.tvg.json. It is still a JSON file, so every editor and JSON tool handles it, and the .tvg part marks it as a TerraVision Graph. TerraVision also accepts any other file ending in .json. terravision graphdata and the MCP render_graph tool both write .tvg.json files.
-
Node address =
<type>.<name>. The type picks the icon. See node-types.md for the full list; unknown types, including misspelt ones, get a generic icon for their provider without any error. Pick the specific type where Terraform has a generic one, because a graph file carries no attributes to refine it:For Use Not Application / Network Load Balancer aws_alb,aws_nlbaws_lb(generic Elastic Load Balancing icon)ECS on Fargate aws_ecs_fargateaws_ecs_service(generic ECS icon)RDS by engine aws_rds_postgres,aws_rds_mysql,aws_rds_sqlserver,aws_rds_oracle,aws_rds_mariadb,aws_rds_auroraaws_db_instance(generic RDS icon)EKS cluster aws_eks_serviceaws_eks_cluster(draws EC2 instances) -
Connections vs containment. If the source node is a container, its targets are drawn inside it. Otherwise an arrow is drawn from source to target. Container types:
- AWS:
aws_vpc,aws_subnet,tv_aws_az(the older nameaws_azalso works),aws_security_group,aws_autoscaling_group,aws_appautoscaling_target,aws_group,aws_account,tv_aws_region,tv_aws_onprem - Azure:
azurerm_resource_group,azurerm_virtual_network,azurerm_subnet,azurerm_group,tv_azurerm_zone,tv_azure_onprem - GCP:
google_project,google_compute_network,google_compute_subnetwork,google_container_cluster,google_container_node_pool,google_compute_instance_group,google_compute_firewall,tv_gcp_region,tv_gcp_zone, and thetv_gcp_*group boxes in rule 5
Some of these read like single services but are boxes: "
google_container_cluster.gke→google_sql_database_instance.db" draws Cloud SQL inside a GKE box, and an autoscaling group or security group contains its instances. To show a connection to one of them, point the arrow at a node inside it. - AWS:
-
Leaf nodes that only appear as targets may be left out as keys; they are drawn as nodes with no outgoing connections. Listing them with
[]is equivalent, and is the complete form thatterravision graphdatawrites. When a node has numbered copies, target the copies (aws_subnet.private~1): an unnumbered name next to its numbered copies can be drawn as an extra, separate node. -
Numbered copies. Append
~1,~2, ... to make distinct instances that share a name, typically one per availability zone. -
External actors. Use pseudo-types:
tv_aws_users,tv_aws_internet,tv_aws_mobile_client,tv_aws_onprem,tv_azurerm_users,tv_azurerm_internet,tv_azure_onprem,tv_gcp_users_icon. For GCP,tv_gcp_users,tv_gcp_onpremandtv_gcp_external_saasare group boxes that contain other nodes (like a VPC), not single icons, and there is no GCP internet icon yet. -
Regions and zones.
tv_aws_region.<name>,tv_aws_az.<name>,tv_azurerm_zone.<name>,tv_gcp_region.<name>,tv_gcp_zone.<name>are containers. -
Modules. A
module.<modname>.prefix, asterravision graphdatawrites it, is accepted but draws no module boundary; leave it out when writing a graph by hand. -
One provider per graph. The diagram's cloud frame (AWS Cloud, Azure, Google Cloud) and its drawing conventions come from the resource type prefixes. A graph that mixes
aws_*,azurerm_*andgoogle_*resources (including theirtv_*actors) is rejected with an error; draw one diagram per provider. -
Labels and title. Names are prettified automatically (
aws_db_instance.postgres~1becomes "DB Instance Postgres"). Use lowercase snake_case names: hyphens and capitals are mangled (Orders-Tablebecomes "Orders"). Pass--use-tf-namesto label with the raw address instead. The graph cannot carry a title; pass--title(ortitleto the MCP tools), otherwise the heading is "Cloud Architecture Diagram". -
Flows. Numbered steps drawn as badges, with a legend, show how a request or data moves. Pass
flowsto the MCP tools, or put aflows:section in a YAML file and pass--annotate <file>:{"order": {"description": "A customer places an order", "steps": [{"resource": "tv_aws_users.users", "detail": "Customer opens the app"}, {"resource": "aws_alb.api~1 -> aws_ecs_fargate.app~1", "detail": "Request routed to a task"}]}}. A step names a node, or an arrow as<node> -> <node>in either direction; name the numbered copy (aws_alb.api~1), never the bare name. Steps on containers, missing nodes or missing arrows draw no badge and come back as warnings. For a graph, an annotation file may hold onlytitle,flows,connect(labels on existing arrows, rule 11),fontsizeandiconsize; anything that would change the drawing belongs in the graph. Add flows when the user asks how requests, data or events move; otherwise deliver the plain diagram, explain the flow in your reply, and end by offering to add it as numbered steps. -
Edge labels. A few words on an arrow say what the connection does ("Reads secrets", "Publishes events"). Pass
edge_labelsto the MCP tools as{"aws_ecs_fargate.app~1 -> aws_rds_sqlserver.db": "Reads orders"}, or on the command line put them in the annotation file'sconnect:section (connect: {aws_ecs_fargate.app~1: [{aws_rds_sqlserver.db: Reads orders}]}). Either direction names the arrow. A label never adds an arrow: one on a missing arrow, or an arrow to a container, is not drawn and comes back as a warning. Add labels when the user asks what the connections do; otherwise offer them together with flows after delivering the diagram.
TerraVision draws a graph file as written. Unlike a diagram from Terraform code, nothing is added, moved, grouped or merged for you. A few drawing rules still apply and explain most surprises:
-
Shared services have no arrows. Arrows to or from these types are not drawn, because almost everything talks to them and the lines would cover the diagram:
- AWS:
aws_cloudwatch_log_group,aws_ecr_repository,aws_acm_certificate,aws_kms_key,aws_ssm_parameter,aws_efs_file_system,aws_eip - Azure:
azurerm_key_vault,azurerm_monitor,azurerm_log_analytics_workspace,azurerm_container_registry,azurerm_storage_account - GCP:
google_kms_key_ring,google_logging_project_sink,google_monitoring_dashboard,google_container_registry,google_secret_manager_secret
On AWS and Azure, list them in
aws_group.shared_servicesorazurerm_group.shared_servicesto draw them together in a Shared Services box; otherwise they float on their own. A few source types, such asaws_ecs_serviceandaws_alb, keep their arrows to a shared service. - AWS:
-
Arrows to a container are not drawn.
aws_lambda_function.fn → aws_vpc.mainshows nothing; point at a node inside the container. -
A node sits in one container. Listing it under two subnets draws it in only one of them; use numbered copies (
aws_alb.web~1,aws_alb.web~2) for one per subnet. -
Zones follow the cloud. On AWS a subnet belongs to one availability zone (
tv_aws_azholdsaws_subnet), so a resource that spans zones gets one numbered copy in each zone's subnet: load balancers, NAT gateways, ECS or EC2 tiers and Multi-AZ databases (aws_alb.web~1inaws_subnet.public~1,aws_alb.web~2inaws_subnet.public~2), with arrows pointing at the copies. On Azure and GCP a subnet spans the region's zones: draw zone-redundant or regional services (Application Gateway, NAT gateway, load balancers, managed instance groups) once in their subnet, and put per-zone instances intv_azurerm_zoneortv_gcp_zoneboxes inside the subnet. -
Two-way connections draw one arrow. If A lists B and B lists A, only one direction is shown; list the main direction of flow.
-
Nesting is literal. Edge services (CloudFront, Route 53, API Gateway, WAF) and external actors stay wherever you nest them, so keep them at the top level rather than inside a VPC or subnet. Containers with nothing in them are not drawn.
| Example | Provider | File |
|---|---|---|
| Three-tier web app: CloudFront, ALB, EC2 across two AZs, RDS, ElastiCache | AWS | three-tier-web.tvg.json |
| Event-driven order pipeline: API Gateway, Lambda, SQS, SNS, DynamoDB, Firehose, Glue, Athena | AWS | aws-event-driven.tvg.json |
| Three-tier web app: Front Door with WAF, Application Gateway, Container Apps across two zones, Azure SQL via private endpoint, NAT gateway | Azure | azure-three-tier.tvg.json |
| Web app with Front Door, App Service, Functions, SQL, Service Bus, Key Vault | Azure | azure-web-app.tvg.json |
| Three-tier web app: HTTPS LB with Cloud Armor, managed instance group across two zones, Cloud SQL, Memorystore, Cloud NAT | GCP | gcp-three-tier.tvg.json |
| Serverless API: HTTPS LB, Cloud Run, Cloud SQL, Pub/Sub, Cloud Functions, BigQuery | GCP | gcp-serverless-api.tvg.json |
Mermaid draws boxes and arrows. It has no notion of the AWS, Azure or GCP icon sets, of VPC and subnet nesting, or of the layout conventions cloud architects expect. TerraVision produces the diagram a cloud architect would draw by hand, from a JSON file an LLM can emit in one shot.
That advantage only applies to cloud infrastructure. For sequence diagrams, flowcharts, class or ER diagrams, code structure or anything that is not AWS, Azure or GCP resources, Mermaid or a similar tool remains the right choice.
If you have Terraform, terravision graphdata --source ./tf --outfile architecture.tvg.json exports the real graph in exactly this format, so the same tooling works for diagrams of what is actually deployed.