Docs & Code Guide

A living diagram from AWS CDK: synth output vs the construct tree, and which one to diagram

Every cdk synth produces two descriptions of your app. The CloudFormation templates in cdk.out are the deploy truth, flattened to raw resources. cdk.out/tree.json is the construct hierarchy, the app as its authors structured it. For a diagram people read in a wiki, the tree wins, because it preserves the abstractions the template destroys. Here is how to use it, and how to regenerate the diagram every time synth runs.

8 min readFor teams building AWS infrastructure with CDK constructs

See it as a diagram

Everything below, as a diagram you can edit. Describe yours and see it in seconds.

239/20003 credits left
Try:

No account needed · Editable canvas, not a picture

Two artifacts from one synth, answering different questions

cdk synth compiles your TypeScript or Python into CloudFormation templates under cdk.out, one per stack. That output answers "what will AWS create". Alongside it, the CLI writes cdk.out/tree.json, a JSON tree of every construct in the app: each node with its id, its path, its children, and a constructInfo block whose fqn names the construct class, aws-cdk-lib.aws_lambda.Function and so on. That file answers "how the authors structured the system", which is the question a diagram exists to answer.

The root of the tree is the App, its children are the stacks, and everything nests below. Two jq lines get you oriented.

npx cdk synth

# The stacks in the app
jq '.tree.children | keys' cdk.out/tree.json

# Every construct class used, deduplicated
jq '[.. | .constructInfo?.fqn | select(.)] | unique' cdk.out/tree.json

L1, L2, L3: the construct levels are your grouping for free

CDK constructs come in three levels. L1 constructs (the Cfn* classes) map one-to-one to CloudFormation resources. L2 constructs wrap them with sane defaults, one lambda.Function fans out into the function, its role, and its permissions. L3 constructs, the patterns, bundle whole architectures: an ApplicationLoadBalancedFargateService from aws-ecs-patterns expands to a dozen underlying resources.

This is exactly the altitude problem diagrams struggle with, already solved in the tree. Draw at the L2 and L3 level and the diagram shows one box per thing an engineer would name, with the generated roles, log groups, and permission glue folded inside. The constructInfo.fqn on each tree node tells you which level you are looking at, so an agent generating the diagram can pick the altitude mechanically.

Why hand-annotating the synthesized template loses

The tempting alternative is to diagram the CloudFormation output, then tidy it by hand: merge the noise, rename the hash-suffixed logical IDs, group things back into the constructs they came from. The work is real, roughly reconstructing tree.json manually, and it is destroyed at the next synth, because logical IDs shift and the glue resources reshuffle. Annotation on generated output is a treadmill.

Diagramming from the tree inverts this. The grouping is in the source artifact, so regeneration reproduces it instead of erasing it, and the curation an engineer adds in Datadef, annotations on the tricky parts, a zone for the payment path, survives because the update touches resources, not the layout story. If your deploy pipeline consumes the synthesized templates elsewhere, the CloudFormation living diagram covers the template-side loop.

Regenerate after synth in CI

Synth already runs in CI on every merge, which means the diagram's source artifact is already being produced; the loop is one step behind it. An agent connected to Datadef's MCP server (registry io.datadef/mcp) reads tree.json, updates the diagram, and keeps stack zones and construct grouping intact. The connection needs an API key, available on paid plans; the MCP diagram server guide has the setup.

The honest framing, as everywhere in this series: Datadef does not watch the repo, nothing fires on merge by itself, and the loop is the one command you append after synth. For the very first diagram, before there is one to update, the AWS architecture diagram generator gets you the editable starting point from a description or pasted output.

Where the construct tree falls short

tree.json describes constructs and their hierarchy, but not every runtime edge: an SQS trigger wired through grant methods is visible, while a Lambda calling another service by URL from application code is invisible to CDK entirely. The diagram inherits that blind spot from the source, and the honest fix is a manual annotation on the diagram, not a pretended completeness.

The embed that keeps the wiki current, an image URL refreshing within minutes of a diagram change, exists only for projects shared public; private projects need exported images. And the loop maintains the architecture view, not the prose around it.

Tree for reading, template for deploying

cdk.out/tree.json preserves the abstractions your team wrote; the synthesized template flattens them. Diagram the tree, deploy the template.

FAQ

How do I generate an architecture diagram from a CDK app?

Run cdk synth, then use cdk.out/tree.json as the source: it holds every construct with its id, path, children, and class name. Feed it to an MCP-connected agent or paste the relevant part into a generator to get a diagram grouped by stack and construct, then re-run the same step after each synth to keep it current.

What is cdk.out/tree.json?

A JSON tree the CDK CLI writes on every synth, describing the whole construct hierarchy of the app: the App at the root, stacks as its children, and each construct node carrying a constructInfo.fqn naming its class. It is the machine-readable version of how the app is structured, as opposed to the flattened CloudFormation output.

Should the diagram show L1, L2, or L3 constructs?

L2 and L3. L1 constructs map one-to-one to raw CloudFormation resources and drown the diagram in roles, permissions, and log groups. L2 constructs are the named things engineers reason about, and L3 patterns bundle whole sub-architectures into one meaningful box. The fqn on each tree node identifies the level.

Why not diagram the synthesized CloudFormation template instead?

Because the template flattens the abstractions and decorates logical IDs with hashes, so any manual tidying is redone after every synth. The construct tree keeps the grouping in the source artifact, which makes regeneration reproduce the structure instead of erasing your cleanup.

Does the CDK diagram update automatically on merge?

No. Nothing watches the repository. The regeneration is one CI step after cdk synth: an agent reads cdk.out/tree.json and updates the diagram through MCP. Wiki pages embedding the diagram then refresh within minutes on their own.