Skip to content
Connect an agent

Infrastructure as code

Pulumi

How to draw a Pulumi stack as a Plotwork diagram that is published again whenever the stack's outputs change. Pulumi runs the Plotwork Terraform provider through its Any Terraform Provider package, so a TypeScript or Python program gets the same resources as Terraform. It is for platform engineers who keep their infrastructure in Pulumi.

TL;DR

QuestionAnswer
How do I add it?pulumi package add terraform-provider registry.terraform.io/plotwork-official/plotwork 0.1.0-beta.2, in the project folder.
Which Pulumi?3.147.0 or later. Tested with 3.272.0, TypeScript on Node.js 22 and Python 3.14.
What do I get?plotwork.Diagram publishes, getRender turns source into an SVG, getImport turns files into source, and the organisation's brand, icons and patterns as resources.
Where can the SVG go?Anywhere a Pulumi resource can write, such as aws.s3.BucketObjectv2.
How does it sign in?pulumi config set --secret plotwork:apiKey pw_..., or PLOTWORK_API_KEY.
Which plan?Publishing works on every plan. Rendering and importing need Pro or above.
Does pulumi preview need a key?Not for a diagram built from outputs that do not exist yet. A render or import whose input is already known is called during the preview, so it needs a key.
Is there an example?examples/pulumi/typescript-stack-diagram (opens in a new tab) in the examples repository.

1. Add the provider

Run this in the folder that holds Pulumi.yaml:

shell
pulumi package add terraform-provider registry.terraform.io/plotwork-official/plotwork 0.1.0-beta.2

It generates an SDK in sdks/plotwork, links it into the project as the dependency @pulumi/plotwork for Node.js, or as sdks/plotwork in requirements.txt for Python, and records the package in Pulumi.yaml:

yaml
packages:  plotwork:    source: terraform-provider    version: 1.5.0    parameters:      - registry.terraform.io/plotwork-official/plotwork      - 0.1.0-beta.2
RuleWhy
Give the full address, registry.terraform.io/plotwork-official/plotworkThe short form plotwork-official/plotwork looks in the OpenTofu registry, which does not carry the provider, and fails with "does not have a provider named".
Give the exact version0.1.0-beta.2 is a pre-release. It talks to https://api-preview.plotwork.dev by default, and needs a key from the preview portal.
Commit Pulumi.yaml, not sdks/pulumi install generates the SDK again from the packages entry on a fresh checkout or in CI.

2. Sign in

Keep the key in the stack's configuration as a secret, so pulumi up and pulumi destroy both have it:

shell
pulumi config set --secret plotwork:apiKey pw_...pulumi config set plotwork:organization acme   # only to publish to an organisation's library
ConfigVariableWhat
plotwork:apiKeyPLOTWORK_API_KEYA personal key from API keys, or an organisation key from Keys and CI
plotwork:organizationPLOTWORK_ORGThe organisation a diagram publishes to when it names none. Needed with an organisation key
plotwork:apiUrlPLOTWORK_API_URLAnother API address

Set the key before the first pulumi up. Pulumi keeps the provider's settings from the last update, and pulumi destroy uses those.

3. Draw the stack's outputs in TypeScript

Build the source from your resources' outputs. Pulumi publishes the diagram after them, and again when one of them changes. With a bucket set, it also renders the SVG and writes it to S3:

typescript
import * as aws from "@pulumi/aws";import * as plotwork from "@pulumi/plotwork";import * as pulumi from "@pulumi/pulumi";
const config = new pulumi.Config();const organization = config.get("organization");const bucket = config.get("bucket");
// Your resources' outputs: vpc.cidrBlock, lb.dnsName, db.address.const deployment = pulumi.output({ vpcCidr: vpc.cidrBlock, lbDnsName: lb.dnsName, dbEndpoint: db.address });
const source = deployment.apply((d) => [  'flow "Production network"',  'node users person "Users"',  `node lb gateway "Load balancer" sub="${d.lbDnsName}"`,  `group vpc "VPC ${d.vpcCidr}" type=network {`,  '  node app service "App"',  `  node db database "PostgreSQL" sub="${d.dbEndpoint}"`,  "}",  'users -> lb : "HTTPS"',  'lb -> app : "routes"',  'app -> db : "queries" role=data',  "",].join("\n"));
const diagram = new plotwork.Diagram("network", {  source,  name: "Production network",  folder: "Platform/Network",  scheme: "auto",  ...(organization === undefined ? { alias: "prod-network" } : { organization, classification: "internal" }),});
export const link = organization === undefined ? diagram.stableUrl : diagram.viewUrl;
if (bucket !== undefined) {  const picture = plotwork.getRenderOutput({ source, scheme: "auto" });  new aws.s3.BucketObjectv2("network-svg", {    bucket,    key: "diagrams/network.svg",    content: picture.svg,    contentType: "image/svg+xml",  });}

The writing diagrams guide describes the language. The example in the examples repository runs this program with a stand-in for the stack, so it needs no cloud account.

4. The same in Python

pulumi package add writes sdks/plotwork into requirements.txt and installs it as pulumi_plotwork:

python
import pulumiimport pulumi_aws as awsimport pulumi_plotwork as plotwork
config = pulumi.Config()organization = config.get("organization")bucket = config.get("bucket")
# Your resources' outputs.deployment = pulumi.Output.all(vpc_cidr=vpc.cidr_block, lb_dns_name=lb.dns_name)

def to_source(d):    return "\n".join([        'flow "Production network"',        'node users person "Users"',        f'node lb gateway "Load balancer" sub="{d["lb_dns_name"]}"',        f'group vpc "VPC {d["vpc_cidr"]}" type=network {{',        '  node app service "App"',        "}",        'users -> lb : "HTTPS"',        'lb -> app : "routes"',    ]) + "\n"

source = deployment.apply(to_source)
diagram = plotwork.Diagram(    "network",    source=source,    name="Production network",    folder="Platform/Network",    scheme="auto",    organization=organization,    classification="internal" if organization else None,)pulumi.export("link", diagram.view_url if organization else diagram.url)
if bucket:    picture = plotwork.get_render_output(source=source, scheme="auto")    aws.s3.BucketObjectv2(        "network-svg",        bucket=bucket,        key="diagrams/network.svg",        content=picture.svg,        content_type="image/svg+xml",    )

5. Publish to an organisation's library

Set organization on the diagram, or plotwork:organization for the whole stack. The diagram goes to that organisation's private library, and viewUrl (view_url in Python) is the portal page its members open. An organisation's diagram has no public url and takes no alias; a stable link is for a personal library. classification sets public, internal or confidential.

Limits

LimitWhat to do
The provider is a pre-release, 0.1.0-beta.2, and talks to Plotwork's preview APIUse a key from the preview portal, or set plotwork:apiUrl
Each change to the source publishes a new diagram and deletes the old one, but Pulumi keeps the resource's first idRead links from url, stableUrl and viewUrl, never from id
getRender and getImport need Pro or above, and run during pulumi preview when their input is knownKeep a key in the stack's configuration for previews in CI
The generated SDK is local to the projectRun pulumi install after a fresh checkout
What a render, an import or a publish sends leaves your networkSend source and configuration, never state or secrets

See also

PageWhy
Terraform providerThe same provider in Terraform and OpenTofu, and every argument
Hosted diagramsLinks, stable links and how long diagrams are kept
OrganisationsPrivate libraries, roles and organisation keys
Writing diagramsThe language for the source your program builds