PlantUML Activity Diagram Syntax & Examples
Reference for PlantUML activity diagram syntax — start / stop, actions, if-else branches, repeat-while loops, switch-case, and swimlane lanes. Copy-paste examples.
Use this page to connect a high-intent search query to the right problem-solution narrative.
A syntax reference for the PlantUML activity-beta grammar — read this when you need to know exactly how a particular construct (decision, loop, lane, fork) is written, then beautify or edit the source in the editor.
View PlantUML sourcePlain-text diagram syntax — copy or edit directly.
1@startuml2|Employee|3start4:Submit reimbursement;5|Manager|6:Review request;7if (Approved?) then (yes)8 |Finance|9 :Process payment;10 :Notify employee;11else (no)12 |Employee|13 :Receive rejection;14endif15stop16@endumlWhat is a PlantUML activity diagram
An activity diagram in PlantUML describes a process as an ordered sequence of actions, with branches, loops, and parallel paths along the way. It is the closest PlantUML equivalent to a flowchart — but with a strict grammar (`start` / `:action;` / `stop`) and built-in support for swimlane lanes, which makes it the standard choice for runbooks, approval flows, and process documentation. PlantUML actually ships two activity syntaxes: the legacy one (using `(*)` and arrow notation) and the modern activity-beta (start / action / stop). Everything on this page covers activity-beta, which is what `@startuml` / `@enduml` blocks render by default in current PlantUML releases.
Basic syntax — start, action, stop
Every activity diagram lives inside a `@startuml` / `@enduml` block. The flow begins at `start`, runs through a series of actions written as `:Action text;` (note the trailing semicolon), and ends at `stop` (or `end` for early termination). Actions can be plain strings, multi-line with `\n`, or include inline formatting. Each action becomes one rounded rectangle in the rendered output, and the renderer connects them top-to-bottom by default. This is the minimum viable activity diagram and the building block every other construct extends.
- `start` and `stop` are required terminals — omit them and the parser falls back to legacy syntax
- `:Action;` is the basic activity node — text inside the colons, semicolon at the end
- Multi-line action labels use `\n` inside the colons
Branching — if-else and switch-case
Decisions in PlantUML activity use `if (Condition?) then (yes) ... else (no) ... endif`. The condition is rendered as a diamond, and the `(yes)` / `(no)` labels appear on the outgoing edges. For multi-way decisions, use `switch (Variable?) ... case (A) ... case (B) ... endswitch` — each case becomes a separate path that converges at the end of the switch. Both forms can be nested and combined with loops; the parser handles arbitrarily deep nesting, but practical readability degrades past two levels.
- `if (Condition?) then (yes) ... else (no) ... endif` — basic two-way decision
- `if (...) then (yes) ... elseif (...) then (yes) ... else (no) ... endif` — chained decisions
- `switch (...) case (A) ... case (B) ... endswitch` — multi-way decision with named branches
Looping — repeat-while and while-do
PlantUML activity offers two loop constructs that differ in when the condition is evaluated. `repeat ... repeat while (Condition?) is (yes)` runs the body first, then tests — equivalent to a do-while loop. `while (Condition?) ... endwhile` tests first, then runs the body — equivalent to a standard while loop. The first form is typical for retry patterns (attempt the action, then check whether to retry); the second is typical for queue processing (check whether there's work, then process it). Both forms accept an optional `->no;` or `->yes;` annotation on the exit edge to label what the false condition means in context.
Swimlane lanes — partition responsibility across actors
Swimlane lanes are PlantUML activity's standout feature. Declare a lane with `|Lane Name|` before the first action that belongs in it; subsequent actions belong to the most recently declared lane until another `|Other Lane|` switches context. Optionally tint the lane with `|#Color|Lane Name|` — colors can be named CSS values or hex. The reference renderer stacks lanes vertically as subgraphs, but Beauty Diagram's renderer lays them out as horizontal columns by default once at least two lanes and one cross-lane edge are present. That column layout is what makes the diagram read as a process across actors rather than a vertical sequence with labels.
- `|Customer|` — plain lane declaration
- `|#FFB6C1|Monitoring|` — coloured lane declaration with hex tint
- `|Lane Name|` re-used later switches the active lane without redefining it
Common patterns & gotchas
A few patterns come up repeatedly. Approval flows usually combine swimlanes with `if-else` — the approver lane has the decision, the receiver lane handles each outcome. Retry flows pair `repeat-while` with a status check. Forks and joins for parallel paths use `fork ... fork again ... end fork` — supported but rendered with default layout, not yet beautified. The most common gotcha: forgetting the semicolon on `:Action;` causes the parser to swallow the entire next line silently — if your diagram is missing a node, check the previous line for a missing `;` first.
- Missing `;` on `:Action;` silently swallows the next line — most common syntax bug
- Lanes only switch to horizontal columns when ≥ 2 lanes + ≥ 1 cross-lane edge exist
- `stop` inside a branch terminates only that branch path, not the whole diagram