Diagrams

Your architecture diagram belongs in the repository

TALA went open source last week. That is a good excuse to explain why every diagram we hand a client is a text file under version control, and why the ones that are not are always out of date.

On 7 September the Terrastruct team open-sourced TALA, the layout engine for D2. It was the one paid piece of an otherwise free tool; it is now MPL-2.0, the same licence as D2 itself, bundled in D2 v0.9.0 and selected with --layout=tala. The discussion on Hacker News ran to a few hundred points, mostly people who had wanted exactly this.

We have used D2 internally for about two years, so this is a good moment to explain why — because the argument is not really about diagrams. It is the same argument we make about firewalls and about servers.

The problem is not drawing, it is drift

Every estate we inherit has an architecture diagram. It is a PNG in a wiki, or a .drawio file somebody exported once, or a Visio document that only opens on one person’s laptop. It is always wrong, and it is wrong in a specific way: it describes the system as it was on the day somebody had time to draw it.

Nobody updates it, because updating it means opening a drawing program, finding the right box, moving the arrows so they do not overlap, exporting, and uploading. That is fifteen minutes of fiddling for a change that took one line of configuration. So it does not happen.

A diagram that is a text file has a different failure mode: it goes stale in the same commit that changes the system, where a reviewer can see it. That is the whole benefit. nixos-rebuild and the diagram move together or the difference shows up in the pull request.

What it looks like

Here is a real shape of thing we draw — a client’s laptop reaching a host over WireGuard, and that host shipping backups to a second country:

direction: right

goteborg: Göteborg {
  laptop: ThinkPad
}

sto: you.sto — Stockholm {
  nginx
  redmine: Redmine
  pg: PostgreSQL {shape: cylinder}
  nginx -> redmine -> pg
}

cra: craiova.cra — Romania {
  backup: Backup target {shape: cylinder}
}

goteborg.laptop -> sto.nginx: wg0
sto.pg -> cra.backup: nightly, encrypted

That is the entire source. It produces this:

A diagram: a ThinkPad in Göteborg connects over wg0 to a Stockholm host running nginx, Redmine and PostgreSQL, which ships nightly encrypted backups to a target in Craiova.

Nineteen lines, and the layout is not our problem. Add a second host and the arrows rearrange themselves.

Two more that earn their keep

A migration, before and beside after. This is the diagram that does the most work in a proposal, because the left side is what the client is paying for now:

before: Before — eu-west-1 {
  alb: Application Load Balancer
  ecs: ECS tasks
  rds: RDS Postgres {shape: cylinder}
  s3: S3 {shape: cylinder}
  alb -> ecs -> rds
  ecs -> s3
}

after: After — Falkenstein + Stockholm {
  pf: pf
  nixos: NixOS host
  pg: PostgreSQL {shape: cylinder}
  minio: MinIO {shape: cylinder}
  pf -> nixos -> pg
  nixos -> minio
}

before -> after: one service a week, rehearsed rollback

An estate, with the evidence attached. NIS2 Article 21(2)(a) wants risk analysis and security policies written down. An assessor does not want a picture; they want to know the picture is generated from the same repository as the thing it describes:

net: Perimeter {
  pf: pf ruleset
  wg: WireGuard mesh
}

hosts: Hosts declared in one repository {
  a: you.sto
  b: kalmar.sto
  c: craiova.cra
}

net.pf -> hosts.a
net.pf -> hosts.b
net.wg -> hosts.c: site-to-site
hosts -> audit: nixos-rebuild --target-host
audit: "Every change is a commit" {shape: document}

All three compile — we checked them against d2 before publishing this, which is a habit worth having with any example you put on the internet.

Where it is honestly weaker

The announcement is unusually candid about TALA’s limits, and we would repeat them rather than bury them. It uses randomness, so a small change to the source can produce a noticeably different layout. It handles directed acyclic graphs worse than Dagre or ELK — the very case most infrastructure diagrams fall into. And it scales nonlinearly, so a large diagram gets slow.

That matches our experience. We reach for --layout=elk for anything that is mostly a flow, and TALA for the messier network pictures where its willingness to move things around pays off. Both are one flag.

The broader caution is that automatic layout does not rescue a diagram that is trying to show too much. If your picture has sixty nodes, the problem is the picture. D2 will lay out your sixty nodes very tidily and nobody will read them.

When we would not use it

If a diagram is drawn once for a pitch and thrown away, use whatever is fastest — the version-control argument does not apply to something with no second version. If your team genuinely collaborates on diagrams visually, in real time, a canvas tool is a better fit and we would say so.

And if the diagram is not generated from, or reviewed alongside, the thing it describes, then it does not matter which tool drew it. It will be wrong within a quarter. That is the actual point, and it was true before last week’s licence change.

Nästa steg

Tell us what you are running.
We will tell you what it should be.

A first conversation costs nothing and takes forty minutes. You will leave it with an honest opinion about your stack — including, occasionally, that you should change nothing at all.