A new simple approach to diagram as code on AWS with CDK and D2

A diagram should convey a clear message about the intention of the architecture. For this message, you only need a few primary resources. Most generated diagrams are overloaded. This new app generates a diagram as code from your annotations in the CDK code.

When I am doing AWS Training, participants often state the wish that diagrams are automatically drawn from AWS resources. As this is possible with solutions like cfn-diag, the generated diagrams usually need more information to be helpful. A diagram should convey a clear message about the architecture’s intention. For this message, you only need a few primary resources. The other “glue” resources are necessary for the proper functions but not to show the logical view of a diagram.

The traditional approaches to this problem are:

  1. Only use it if you have a small number of resources, like the CloudFormation drawing tool.


  1. Filter resources from the diagram afterwards, like cfn-dia


  1. Draw manually

All solutions have a low degree of automation and do not synchronize with changes in the infrastructure.

A helpful solution should:

  1. be fully automated, with no manual steps
  2. Be 100% synched with deployed resources. Show what is and not what should be
  3. Take meaningful names from the Code part of Infrastructure as Code. The often used CloudFormation logical ID is not helpful.

And my main requirement:

  1. Show only those resources which I think are needed, to show the main purpose of the architecture

A simple approach to DaC

  1. Generate D2 code from CDK code. D2 will take care of rendering.

  2. Poll CloudFormation for the deployment status of the resource. Only resources which are beeing created or are created are shown.

  3. Use the CDK Construct ID as title for a resources, not the logical ID or the physical ID.

  4. Add very few information to the CDK code, to keep thinks simple:

  • Show - the Construct is shown on the diagram
  • Connection - a connection is drawn from source Construct to target Construct
  • Contains - Resources like a VPC, which contain other resources

Example with a serverless architecture

I take simple serverless architecture as a starting point.

These are the lines added for the diagramm information into the TypeScript file:

import * as d2 from "../lib/d2";
d2.Connection(bucky, topic)
d2.Connection(topic, fnTS)
d2.Connection(topic, fnGO)
d2.Connection(topic, fnPy)
d2.Connection(fnTS, table)
d2.Connection(fnGO, table)
d2.Connection(fnPy, table)

We have a S3 Bucket named “bucky”, some Lambda FNunctions, a SNS topic and a DynamoDB table.

And I copy a small TypeScript file into the lib directory.

I deploy the infrastructure:

cdk deploy

Then I generate a d2 diagramm description with cdk2d2:

 cdk2d2 generate adotstarter-auto .

Where the first parameter is the name of the stack and the second parameter is the directory of the CDK app. This creates a file adotstarter-auto.d2.

With d2 I generate a png of this file:

d2 adotstarter-auto.d2 adotstarter-auto.png

Now we got:


instead of the quite confusing CloudFormation diagram:


You see on first sight what the architecure is doing and the name of the Functions are not adotstartergo2987B222, which would be the CloudFormation logical ID, but the Construct ID from the code:

const fnGO = new aws_lambda.Function(this, 'adotstarter-go', {

Inside cdk2d2


With the information from the CDK manifest file from the cloud-assembly, q construct like the lambda function “fnGO” is generated as D2:

adotstartergo2987B222: adotstarter-go{
 icon: https://icons.terrastruct.com/aws%2FCompute%2FAWS-Lambda_Lambda-Function_light-bg.svg

Where the id of the artefact is the cfn logicalid and the title is the CDK construct ID. The icon is set according to the CloudFormation Resource type. See icon.go for mappings. The color style.fill is set according to the deployment state of the resource.

So when you change the name of the construct, the diagram is updated with the new name.

You define the resources which should be shown on the diagramm in your code, because only you know which resources are the main resources. For example the helper lambda which CDK uses to set the retention time on the CloudWatch logs should usually now be shown.

Now to the synchronisation part

I destroy the stack. Now we use three terminal windows:

  1. cdk2d2 Script generator
  2. d2 rendering
  3. CDK deploy.

All running in the same CDK app base directory.

Terminal 1

On terminal 1 we start:

cdk2d2 watch adotstarter-auto .

This will update the stackname.d2 each 4 seconds with then current deployment state of the construct resource.

Terminal 2

On this terminal we start the rendering process with:

d2 --watch adotstarter-auto.d2

This will open a browser windows, where d2 renders the live state of the stack.de diagram.

Terminal 3

Here we start the CDK deployment.

cdk deploy

First picture

Will show nothing, because the stack does not exists.

Second picture

Will show the stack in the upper left with the total number of resources and the deployment percentage.

Stack only

Life state change

Life 1

Resources which are beeing created are colored yellow.

Life 2 Resources which are created are colored green.

Fully deployed state

Life 3

100% resources created.

For each resource you will see the deployment status as color. This way you can watch CloudFormation deploying your resources. The order of the deployment will surprise you sometimes…


The metainformation are stored as metadata:


resource.node.addMetadata("Show", "true")


resource.node.addMetadata("Connection", otherResource.node.id)


resource.node.addMetadata("Container", otherResource.node.id)

Container example

Of course we are talking about a graphical container!


For a VPC you add a “Container” relationship. Only one level is supported, so vpc-subnet will not work.

Now try it out for yourself

Please send suggestions, errors, images for the gallery etc. Add prs for new features to cdk2d2 issues. There are also some more examples. Releases can be found here.

If you like it, please star the repo!

Happy building!

If you need consulting for your serverless project, don’t hesitate to get in touch with the sponsor of this blog, tecRacer.

For more AWS development stuff, follow me on dev https://dev.to/megaproaktiv. Want to learn GO on AWS? GO here

See also

Similar Posts You Might Enjoy

Going on an Industry Quest: Manufacturing and Auto

Using Industry Quest: Manufacturing and Auto you can learn about building IoT and factory management solutions in AWS. It’s a game that teaches you about real time monitoring, predictive maintenance, machine learning and data analytics. This blog gives an introduction to the game and covers my thoughts about its usefulness. - by Maurice Borgmeier

How To Hybrid! - Secure AWS Environment Service Access

As AWS Cloud adoption becomes more widespread throughout the industries, challenges arise how to govern IT resource usage and implement a coherent management for systems across on-premises and the AWS Cloud. This blog post gives insights in how the AWS offered Systems Manager capabilities could be extended from the cloud environment to your hybrid and on-premises environments. - by Marco Tesch

Darf ich als deutscher Finanzdienstleister in die Cloud?

Viele Unternehmen und insbesondere solche in der Finanzbranche stellen sich die Frage, ob sie ihre IT oder Teile dieser überhaupt in die Cloud migrieren dürfen. Ja, die Cloud skaliert gut, sie schafft bessere Verfügbarkeit lokal wie global, sie fördert Agilität, erleichtert den Zugang zu neuen Technologien und kann in vielen Fällen auch Sicherheitsvorteile schaffen. Aber wie die rechtliche Situation bei einer Auslagerung an Public Cloud-Anbieter aussieht, steht nochmal auf einem anderen Blatt Papier. - by Benjamin Wagner