PlantUML Syntax Cheat Sheet: 10 Diagrams, Tested

On this page
  1. The skeleton
  2. Sequence diagram
  3. Class diagram
  4. Activity diagram
  5. State diagram
  6. Component and deployment diagram
  7. Use case diagram
  8. ER diagram (information engineering)
  9. Gantt, mind map and JSON
  10. Styling: themes and skinparam
  11. Mistakes that fail silently
  12. Does PlantUML need Graphviz?
  13. The same lines in Mermaid
  14. PlantUML in Jira and Confluence
  15. How we tested

The class diagram in the architecture docs looks fine on the laptop that wrote it. The CI job builds the same file and the boxes come out in different places. No error, no warning. The runner has no Graphviz, and PlantUML quietly drew the diagram with its built-in layout engine instead.

This is the PlantUML syntax people search for, on one page, with every snippet rendered rather than copied from the docs. We ran it all through PlantUML 1.2026.9 (the current release) on 10 November 2026, plus six common mistakes to see which ones PlantUML actually tells you about.

Short answer: every diagram sits between @startuml and @enduml (Gantt, mind map and JSON have their own @startgantt, @startmindmap, @startjson). Messages are A -> B : text, class relations A <|-- B, activities :step;, states [*] --> Open. Tested in PlantUML 1.2026.9: a missing endif is closed for you with no error, and without Graphviz PlantUML quietly switches layout.

The skeleton

@startuml
title Optional title
' a one-line comment
/' a comment
   over several lines '/
Alice -> Bob : hello
@enduml
  • One diagram per @startuml … @enduml pair. A file can hold several pairs.
  • PlantUML guesses the diagram type from the lines inside, so the same @startuml starts a sequence, class or state diagram.
  • \n inside a label breaks the line: Alice -> Bob : line one\nline two gave two lines in our test.

Sequence diagram

@startuml
title Checkout
actor User
participant "Web app" as Web
database Orders
autonumber
User -> Web ++ : Place order
Web -> Orders : INSERT order
Orders --> Web : id 42
alt card accepted
  Web --> User : Order confirmed
else card declined
  Web --> User : Try another card
end
deactivate Web
note right of Orders : one row per order
@enduml
SyntaxMeaning
participant, actor, database, queue, boundary, control, entityParticipant shapes
participant "Web app" as WebA long name with a short alias
A -> B : textMessage (solid arrow)
A --> B : textReply (dotted arrow)
A -> B ++ / deactivate BStart and end an activation bar
autonumberNumber the messages from here on; the docs: “The keyword autonumber is used to automatically add an incrementing number to messages.”
alt / else / endAlternatives; also opt, loop, par, break, critical, group
note right of X : textA note; also left of, over X, Y

Class diagram

@startuml
class Order {
  - id : int
  - total : Money
  + pay() : void
}
interface Payable {
  + pay() : void
}
abstract class Entity
enum Status {
  NEW
  PAID
}
Entity <|-- Order
Payable <|.. Order
Order "1" *-- "many" LineItem : contains
Order o-- Customer
Order --> Status
@enduml
ArrowRelation
<|--Extension (inheritance)
<|..Implementation of an interface
*--Composition: “The part cannot exist without the whole”
o--Aggregation: “The part can exist independently of the whole”
-->Association or dependency
..>Dependency (dashed)
"1" *-- "many"Multiplicity on either end

Visibility in front of a member: - private, # protected, ~ package private, + public. PlantUML draws them as icons (the red square and green circle in the render above).

Activity diagram

@startuml
start
:Receive request;
if (Valid?) then (yes)
  :Process;
  fork
    :Send email;
  fork again
    :Update stock;
  end fork
else (no)
  :Reject;
  stop
endif
while (More items?) is (yes)
  :Pack item;
endwhile (no)
stop
@enduml
  • Each step is :text;, with the semicolon.
  • if / else / endif, while / endwhile, repeat / repeat while, fork / fork again / end fork, start, stop, end.
  • This is the current syntax. The old one, with (*) --> "First", still rendered in our test, but PlantUML’s docs call it “no longer recommended for new diagrams”, and it needs Graphviz.

State diagram

@startuml
[*] --> Open
Open --> InProgress : start
InProgress --> Review : submit
Review --> InProgress : changes requested
Review --> Done : approve
state Done {
  [*] --> Released
}
Done --> [*]
@enduml

[*] is the start or end point, A --> B : event a transition, and state X { ... } a composite state with its own start.

Component and deployment diagram

@startuml
package "Frontend" {
  [Web app] as web
}
node "Server" {
  [API] as api
  database "Postgres" as db
}
cloud "Payments" as pay
interface HTTP
web --> HTTP
HTTP - api
api --> db
api ..> pay : HTTPS
@enduml

[Name] is a component; package, node, cloud, database, folder and frame group things; interface draws the lollipop.

Use case diagram

@startuml
left to right direction
actor Customer
actor "Support agent" as Agent
rectangle Helpdesk {
  usecase "Open ticket" as UC1
  usecase "Attach file" as UC2
  usecase "Close ticket" as UC3
}
Customer --> UC1
UC1 <.. UC2 : <<extend>>
Agent --> UC3
@enduml

left to right direction lays the diagram out sideways, actors on the left. <<extend>> on a dashed arrow is the usual UML label; <<include>> works the same way.

ER diagram (information engineering)

@startuml
entity Customer {
  * id : int <<PK>>
  --
  name : text
}
entity Order {
  * id : int <<PK>>
  --
  * customer_id : int <<FK>>
}
Customer ||--o{ Order
@enduml

||--o{ reads “exactly one to zero or many”. The other ends: |o zero or one, }| one or many, }o zero or many. -- inside an entity draws the line under the key.

Gantt, mind map and JSON

These three have their own start and end tags.

@startgantt
Project starts 2026-11-16
[Design] requires 5 days
[Build] requires 10 days
[Build] starts at [Design]'s end
[Test] requires 4 days
[Test] starts at [Build]'s end
@endgantt
@startmindmap
* Release
** Code
*** Review
** Docs
left side
** Support
@endmindmap
@startjson
{"service": "api", "replicas": 3, "ports": [80, 443]}
@endjson

The Gantt chart is written in sentences (requires 5 days, starts at [Design]'s end); the mind map uses one * per level and left side to switch sides; the JSON diagram draws any JSON you paste.

Styling: themes and skinparam

  • !theme cerulean (or another built-in theme) at the top. Themes “are included into the library”, so they work offline: ours rendered in a container with no network. A theme from elsewhere needs !theme name from <url>.
  • skinparam classBackgroundColor #EFF6FF changes one setting; <style> blocks are the newer way.
  • #lightblue after an element colours that one element.

Mistakes that fail silently

We wrote six common mistakes and ran them through the command-line PlantUML 1.2026.9, rendering SVG. Two failed loudly, two failed silently, two were fine.

Six mistakes we ran through PlantUML 1.2026.9 on 10 November 2026 and what came out. Loud: a typo such as endiff gives the Syntax Error? image, Error line 5 on the command line and exit code 200; a missing @enduml gives no image, No diagram found and exit code 100. Silent: a missing endif draws the diagram with no error and exit code 0; without Graphviz, class, state and use case diagrams are still drawn, with the built-in Smetana layout, and the image says nothing, while the -testdot check claims only sequence diagrams will be generated. Fine: the legacy activity syntax still renders, and !theme cerulean works with no network because themes are bundled.
  1. A typo (endiff) fails properly. The image becomes PlantUML’s error page with the line and “Syntax Error? (Assumed diagram type: activity)”, the command line prints Error line 5 in file, and the exit code is 200. Rendering a whole folder with one bad file also exits with 200.
  2. No @enduml: no image is written at all. The command line prints Warning: no image in /data/t1-no-enduml.puml and No diagram found, exit code 100. A tool that ignores the exit code keeps the old image or a broken link.
  3. No endif: the diagram is drawn as if the endif were there, with exit code 0 and no warning. Harmless here, but the branch may not end where you meant.
  4. No Graphviz: also silent, see the next section.
  5. The legacy activity syntax still works.
  6. A theme with no network works: we ran it in a container with networking switched off.

In CI, let a non-zero exit code fail the build; that catches the first two. The other two only show when someone looks at the picture.

Does PlantUML need Graphviz?

PlantUML’s own page lists the diagrams that need it: “Usecase diagrams”, “Class diagrams”, “Object diagrams”, “Component diagrams”, “Deployment diagram”, “State diagrams” and “Legacy activity diagrams”. “For all other diagrams, GraphViz is not needed nor used.” It also has a built-in alternative, Smetana, “the internal Java port of GraphViz/Dot embedded in PlantUML sources”, which you switch on per diagram with !pragma layout smetana.

We pointed PlantUML 1.2026.9 at a Graphviz that does not exist. Its own check, -testdot, answered:

Error: Dot executable does not exist
Error: only sequence diagrams will be generated

That is no longer true. The class, state, use case and legacy activity diagrams all rendered, with no error in the image. The class diagram’s boxes sat at exactly the positions that !pragma layout smetana gives, not where Graphviz puts them. So without Graphviz you get Smetana’s layout, silently. It is usually fine, but a diagram can look different on a laptop with Graphviz and on a CI runner without it. Put !pragma layout smetana in the file if you want the same picture everywhere, or install Graphviz on both.

Two other ways to avoid the question: the PlantUML server or Docker image (ours came with Graphviz 14.0.1), and @plantuml/core, PlantUML compiled to JavaScript, which we used in Mermaid vs PlantUML vs D2 vs Graphviz.

One more limit from the FAQ: “PlantUML limits image width and height to 4096.” Set the environment variable PLANTUML_LIMIT_SIZE for bigger diagrams.

The same lines in Mermaid

If the diagram has to live where Mermaid renders and PlantUML does not (GitHub Markdown, many wikis), most basics carry over.

DiagramPlantUMLMermaid
Start@startuml … @endumlsequenceDiagram, classDiagram, stateDiagram-v2, erDiagram, flowchart TD
MessageA -> B : textA->>B: text
ReplyA --> B : textA-->>B: text
Numberingautonumberautonumber
Alternativesalt / else / endalt / else / end
InheritanceA <|-- BA <|-- B
CompositionA *-- BA *-- B
State[*] --> Open[*] --> Open
ER linkA ||--o{ BA ||--o{ B : label
Activity step:Process;A[Process] in a flowchart

The sequence, class and state lines are tested in our Mermaid cheat sheet, which also lists the Mermaid lines that break (a semicolon in a message, a participant called end). Mermaid needs a label on an ER link; the ER and flowchart forms are drawn in both languages in Mermaid vs PlantUML.

PlantUML in Jira and Confluence

Neither renders PlantUML on its own; a PlantUML block shows as code, and Marketplace apps fill the gap. Since November 2026 our own diagram apps draw PlantUML too. They ship the same 1.2026.9 release, compiled to JavaScript (@plantuml/core), with C4-PlantUML 2.14.0 built in, and draw it inside Atlassian with no PlantUML server and no Graphviz to install:

!include works for the C4 library only (!include <C4/C4_Container>); any other include is refused, because nothing is fetched from outside Atlassian. All of these apps are free for up to 10 users. For a side-by-side of the languages, with the same six diagrams in each, see Mermaid vs PlantUML vs D2 vs Graphviz.

How we tested

  • PlantUML 1.2026.9 (PlantUML version 1.2026.9 / 18d0aae) from the plantuml/plantuml Docker image, with Graphviz 14.0.1, on 10 November 2026; SVG output. Every snippet on this page rendered with no error.
  • The six mistakes as separate files. For the Graphviz test we set GRAPHVIZ_DOT to a path that does not exist and compared box positions in the SVG with the same diagram under !pragma layout smetana and under Graphviz.
  • PlantUML’s documentation read the same day: sequence, class, activity, Graphviz, Smetana, themes, FAQ and download.

Frequently asked questions

How do I write a comment in PlantUML?

A line that starts with a single quote is a comment: ' this is ignored. For several lines, open with /' and close with '/.

Does PlantUML need Graphviz?

The docs say use case, class, object, component, deployment, state and legacy activity diagrams need it, and "For all other diagrams, GraphViz is not needed nor used." In our test, PlantUML 1.2026.9 with no Graphviz still drew class, state and use case diagrams, using its built-in Smetana layout, and said nothing in the image. Add !pragma layout smetana to choose that layout on purpose.

Why does PlantUML show "Syntax Error?"

PlantUML could not read a line. The image names the line, and the command line prints "Error line N in file" and exits with code 200. Common causes: a misspelt keyword (endiff), a missing closing keyword in a sequence block, or text in a place PlantUML expects an arrow. Some mistakes do not error at all, such as a missing endif.

How do I convert PlantUML to Mermaid?

By hand, diagram by diagram; the basics map closely. @startuml/@enduml go, and you start with the diagram type instead: sequenceDiagram, classDiagram, stateDiagram-v2, erDiagram. Sequence arrows change from -> and --> to ->> and -->>; class relations (<|--, *--, o--), state transitions ([*] --> Open) and ER links (||--o{) stay the same. Activity diagrams become Mermaid flowcharts.

Is PlantUML free?

Yes. PlantUML is open source, and its download page offers it under GPL, LGPL, Apache, BSD, EPL and MIT licences. The LGPL build is the one without Graphviz embedded.

Can I use PlantUML in Jira or Confluence?

Only through a Marketplace app; Jira and Confluence show a PlantUML block as code. Since November 2026 our Excalidraw UML apps (Jira and Confluence) and our Tabs apps for Jira draw PlantUML inside Atlassian, with C4-PlantUML built in and no PlantUML server.

Keep reading