# Pulumi

> Page: https://docs.plotwork.dev/pulumi. Index of every page: https://docs.plotwork.dev/llms.txt

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](https://docs.plotwork.dev/terraform-provider.md) 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

| Question | Answer |
|---|---|
| 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`](https://github.com/plotwork-official/terraform-plotwork-examples) 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
```

| Rule | Why |
|---|---|
| Give the full address, `registry.terraform.io/plotwork-official/plotwork` | The 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 version | `0.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
```

| Config | Variable | What |
|---|---|---|
| `plotwork:apiKey` | `PLOTWORK_API_KEY` | A personal key from API keys, or an organisation key from Keys and CI |
| `plotwork:organization` | `PLOTWORK_ORG` | The organisation a diagram publishes to when it names none. Needed with an organisation key |
| `plotwork:apiUrl` | `PLOTWORK_API_URL` | Another 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](https://docs.plotwork.dev/writing-diagrams.md) 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 pulumi
import pulumi_aws as aws
import 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

| Limit | What to do |
|---|---|
| The provider is a pre-release, `0.1.0-beta.2`, and talks to Plotwork's preview API | Use 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 `id` | Read 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 known | Keep a key in the stack's configuration for previews in CI |
| The generated SDK is local to the project | Run `pulumi install` after a fresh checkout |
| What a render, an import or a publish sends leaves your network | Send source and configuration, never state or secrets |

## See also

| Page | Why |
|---|---|
| [Terraform provider](https://docs.plotwork.dev/terraform-provider.md) | The same provider in Terraform and OpenTofu, and every argument |
| [Hosted diagrams](https://docs.plotwork.dev/hosted-diagrams.md) | Links, stable links and how long diagrams are kept |
| [Organisations](https://docs.plotwork.dev/organisations.md) | Private libraries, roles and organisation keys |
| [Writing diagrams](https://docs.plotwork.dev/writing-diagrams.md) | The language for the source your program builds |
