Skip to content

PlantUML

A plantuml fence writes sequence, class, component, activity and use-case diagrams; rendering requires a PlantUML server you configure yourself.

A plantuml fence holds PlantUML source. The browser compresses and encodes it, appends it to the URL of a PlantUML server, and gets an SVG back. It suits sequence, class, component, activity and use-case diagrams that need the full expressiveness of UML. Rendering depends on that server: the theme ships no default endpoint, and enable: true without svg_image_url fails the build. With no server available, use Mermaid instead.

This page shows source only, not rendered diagrams

PlantUML has to reach a server you run, and this site assumes no endpoint on the reader’s behalf. In the current theme version the plantuml fence also double-escapes <, >, & and ", so source with arrows or quotes comes back from the endpoint as a Syntax Error? image (see Limits). Every snippet below is correct PlantUML in itself.

Diagrams leave the reader’s browser

The encoded diagram source is sent to the endpoint you configure. Never put passwords, internal hostnames or customer names in a PlantUML fence. Internal sites should run their own endpoint, or use a pre-rendered image.

Shortest form

Sequence diagrams are the most common kind: participant declares a participant, -> is a synchronous message, --> a return.

Source
```plantuml
@startuml
actor Reader
participant Browser
participant Endpoint as Server
Reader -> Browser : open the page
Browser -> Server : GET /plantuml/svg/{compressed source}
Server --> Browser : SVG
Browser -> Browser : replace the fence with an img element
@enduml
```

That draws four lanes and four messages: the reader opens the page, the browser requests the endpoint with the encoded source, the endpoint returns SVG, and the runtime swaps the fence for an image.

Class diagrams

class lists members and "1" -- "0..*" gives a relationship its cardinality — the usual way to explain a data model.

Source
```plantuml
@startuml
class Publication {
  + pubname : name
  + puballtables : bool
  + pubinsert / pubupdate / pubdelete : bool
}
class Subscription {
  + subname : name
  + subconninfo : text
  + subslotname : name
}
class ReplicationSlot {
  + slot_name : name
  + plugin : name
  + confirmed_flush_lsn : pg_lsn
}
Publication "1" -- "0..*" Subscription : subscribed by
Subscription "1" -- "1" ReplicationSlot : bound to
@enduml
```

Three boxes with their fields and two annotated connectors: one publication can serve many subscriptions, and every subscription binds one replication slot.

Component diagrams

package groups deployment units, [component] is a box, and --> is the direction of a dependency.

Source
```plantuml
@startuml
package "Monitoring node" {
  [Grafana] as grafana
  [Prometheus] as prom
  [Alertmanager] as alert
}
package "Database node" {
  [node_exporter] as node
  [pg_exporter] as pgexp
  [PostgreSQL] as pg
}
pg --> pgexp : query the statistics views
node --> prom : /metrics
pgexp --> prom : /metrics
prom --> alert : rule fired
grafana --> prom : PromQL
@enduml
```

Two dashed boxes with three components each, and five labelled arrows tracing the collection path.

Activity diagrams

start / stop with if … then … else … endif draws a branching procedure. This kind contains no arrow characters, so it is the one kind that renders correctly in the current version.

Source
```plantuml
@startuml
start
:write content/docs/**/*.md;
:add the translated peer, copying the rendered heading IDs;
if (hugo --panicOnWarning passes?) then (yes)
  :npm test;
else (no)
  :fix using the file and line in the error;
  stop
endif
if (tests green?) then (yes)
  :open the PR;
  stop
else (no)
  :back to editing;
  stop
endif
@enduml
```

One vertical flow line, two diamonds each branching yes / no, four end points.

Use-case diagrams

actor is a stick figure, (use case) an ellipse, and rectangle draws the system boundary — a good fit for a “who is this for” section.

Source
```plantuml
@startuml
left to right direction
actor Reader as reader
actor Author as author
actor Maintainer as maintainer
rectangle "Documentation site" {
  reader --> (full-text search)
  reader --> (switch language)
  reader --> (export the print view)
  author --> (add a page)
  author --> (preview locally)
  maintainer --> (upgrade the theme)
  maintainer --> (publish)
}
@enduml
```

Three figures on the left, one box with seven ellipses on the right, and connectors saying who can do what.

Colours in dark mode

The server knows nothing about the site’s colour scheme, so the SVG comes back on a fixed white ground. skinparam backgroundColor transparent removes it and the diagram sits on the page background. With neutral lines and text it reads in both modes.

Source
```plantuml
@startuml
skinparam backgroundColor transparent
skinparam defaultFontName sans-serif
skinparam ArrowColor #7C7C7C
skinparam ActivityBorderColor #7C7C7C
skinparam ActivityBackgroundColor #B0BEC522
start
:hugo mod get -u github.com/pgsty/oink;
:hugo --gc --minify;
:upload public/;
stop
@enduml
```

PlantUML’s !theme directive (!theme plain, for instance) also works. Themes come from the server, so a self-hosted endpoint has to have them installed.

The rendering server

The fence itself has no switch; whether it renders depends on the site configuration:

hugo.yml
params:
  plantuml:
    enable: true
    svg_image_url: https://plantuml.internal.example/plantuml/svg/
    svg: false
  • enable: true without svg_image_url fails the build with params.plantuml.enable requires an explicit params.plantuml.svg_image_url. The theme does not pick a public service for the site.
  • To self-host, the official image plantuml/plantuml-server works; point svg_image_url at its /svg/ path and keep the trailing slash — the encoded source is appended to it.
  • The endpoint’s CORS policy and the site’s CSP img-src (plus connect-src when svg: true) must both allow it; use an absolute URL on a subpath deployment.

These keys are defined in Configuration.

Output

Output Shape
HTML The source is emitted as <pre><code class="language-plantuml">; once enabled, the runtime replaces it with an <img> (with svg: true, an <svg data-src>)
Print Same as HTML: the print view loads the runtime and requests the endpoint too
Markdown The plantuml fence and its source, kept as written
RSS The fence source only — subscribers see text

When the feature is off, or the runtime has not loaded, what stays on the page is a readable source block, never a broken-image icon.

Parameter reference

Fence attributes: none. A plantuml fence reads no attribute line and does not go through OINK’s code-block shell, so title, copy and the line-number options from Code blocks have no effect here.

Site parameters (hugo.yml):

params.plantuml.enable , bool , defaultfalse
With it off, the fence stays a code block and no runtime loads
params.plantuml.svg_image_url , string , defaultnone
The rendering endpoint; the encoded source is appended to it. Required when enable: true, otherwise the build fails
params.plantuml.svg , bool , defaultfalse
false inserts <img src>; true inserts <svg data-src> and loads an external SVG loader, putting the SVG in the DOM where CSS can reach it

The theme reads those three keys and nothing else.

Limits

  • <, >, & and " are double-escaped: the current theme version escapes the fence content once too often, leaving literal --&gt; and &#34; in the page and returning a Syntax Error? image from the endpoint. Diagrams with arrows (sequence, component, use case, state) therefore do not render today; activity diagrams, which contain none of those characters, do. Until it is fixed, use Mermaid or a pre-rendered image.
  • A server is mandatory: the theme provides no default endpoint and assumes none.
  • Diagram source leaves the browser: keep anything confidential out of a PlantUML fence.
  • No colour-scheme awareness: the server does not know the reader’s mode, so skinparam is the only lever.
  • No numbering, no zoom: the <img> the runtime inserts does not pass through the image render hook, so {#id num=} and image zoom do not apply.
  • Mermaid — no server, follows the colour scheme, the everyday choice
  • Draw.io — the other integration that needs a server of your own
  • Images — pre-rendered SVG: numberable, zoomable, no external dependency
  • Configuration — the full definition of params.plantuml.*