PlantUML activity diagrams: branching to concurrent

puml.online

Activity diagrams are often overlooked — they’re more powerful than flowcharts. This covers everything from basics to fork/join/exception handling.

Activity vs Flowchart

Dimension Flowchart Activity diagram
Expresses Data / control flow Business activity / workflow / role collaboration
Role separation None partition / swimlane supported
Concurrency Weak Strong (fork / join)
Exceptions Not really Supported
UML standard No Yes

The most basic activity diagram

1
2
3
4
5
6
7
8
9
10
11
12
@startuml
title Place-order flow

start

:user submits order;
:server validates params;
:reserve stock;
:create order;

stop
@enduml
  • start / stop are start / end pseudo-states.
  • :activity; is a single activity, rendered as a rounded rectangle.
  • Multiple activities run sequentially.

Decision nodes

The if (...) then (...) form:

1
2
3
4
5
6
7
8
9
10
11
@startuml
start
:user login;
if (password valid?) then (yes)
:to home;
else (no)
:show error;
:login failed;
endif
stop
@enduml

Multi-branch via switch:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@startuml
start
:choose payment;
switch (method)
case (alipay)
:call alipay api;
case (wechat)
:call wechat;
case (bank)
:call unionpay;
endswitch
:deduct;
stop
@enduml

Loops

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@startuml
start
:retry = 0;
while (retry < 3 && !done?)
:call external api;
if (failed?) then (yes)
:retry = retry + 1;
:sleep 1s;
else (no)
:break;
endif
endwhile
stop
@enduml

PlantUML also has repeat / repeat while:

1
2
3
4
5
6
7
8
@startuml
start
repeat
:ping api;
:sleep 1s;
repeat while (no response?) is (yes) not (no)
stop
@enduml

The is (yes) not (no) decides which branch is true/false.

Concurrency: fork / join

The strongest activity-diagram feature:

1
2
3
4
5
6
7
8
9
10
11
12
@startuml
start
fork
:deduct money;
fork again
:risk check;
fork again
:log;
end fork
:return result;
stop
@enduml

fork / fork again / end fork declares parallel branches.

Joining back:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@startuml
start
:begin;
fork
:task A;
fork again
:task B;
end fork

:merge results;

if (A and B both succeeded?) then (yes)
:next step;
else (no)
:handle failure;
endif
stop
@enduml

The activity after end fork runs only when all branches have completed.

Partitions (swimlanes)

Activities sorted by role — the killer activity-diagram feature:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@startuml
title Order flow — partitioned

|customer|
:place order;

|system|
:validate;
:write to DB;

|warehouse|
:pick;
:pack;

|logistics|
:pickup;
:transport;
:deliver;

|customer|
:receive;

stop
@enduml

|role| switches to that swimlane. Activities are filed in the lane’s column.

Cleaner syntax for grouping:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@startuml
|customer|
start

partition system {
:validate;
:write to DB;
}

partition warehouse {
:pick;
:pack;
}

|logistics|
:pickup;

stop
@enduml

partition X { ... } keeps a group of activities in one lane.

Exception handling

PlantUML activity diagrams support exception paths:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@startuml
start
:submit payment;

if (deduct OK?) then (yes)
:return success;
else (no)
if (network error?) then (yes)
:retry;
else (no)
:log error;
:return failure;
endif
endif
stop
@enduml

Multi-level if/else gets try/catch-like semantics.

If you want “any one fails → exit the whole flow,” use a fork + post-check:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@startuml
start
fork
:task A;
fork again
:task B;
fork again
:task C;
end fork

if (any failed?) then (yes)
:rollback A;
:rollback B;
:rollback C;
:return failure;
else (no)
:done;
stop
endif
@enduml

Real-world example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@startuml
title Content moderation

|creator|
start
:submit content;

|moderation_system|
:preprocess (keyword scan);

if (matched keyword?) then (yes)
:flag for review;
else (no)
:flag approved;
:send notification;
stop
endif

|moderator|
:receive task;
:read content;
switch (verdict)
case (approve)
:flag approved;
case (revise)
:send revision suggestions;
:return to creator;
case (reject)
:flag rejected;
:send reject reason;
endswitch

|creator|
if (got revisions?) then (yes)
:revise content;
|moderation_system|
:re-review;
stop
else (no)
stop
endif
@enduml

Covers three creator paths (approve / revise / reject), four roles, full lifecycle in one image.

Review checklist

  • Start / end clear — both start and stop present?
  • Partitions clean — every role explicitly partitioned?
  • fork / join balanced — every fork matched with an end fork?
  • Parallel branches truly independent?
  • Exception paths marked?
  • Retry loop has a clear termination?

Pitfalls

  • switch must close with endswitch — missing one and the whole diagram fails silently.
  • fork / end fork must balance — missing end fork and downstream :activity; is unmoored.
  • Infinite loops — bare while doesn’t terminate; always pair with if ... break or use repeat ... is (yes) not (no).
  • Too many lane switches — switching roles every other line is unreadable. Use partition X { ... } to group.
  • Long activity names get truncated — split into smaller steps.

vs sequence diagrams

Scenario Pick
One role working through a process Activity
Multiple objects passing messages Sequence
Business workflow (branches, exceptions, loops) Activity
Specific API call sequence Sequence

They complement each other: activity describes the flow; sequence fills in the per-step object interactions.

vs BPMN

BPMN is the Business Process Model and Notation, purpose-built for workflows. PlantUML activity covers ~80% of BPMN’s core:

BPMN PlantUML
Task :name;
Gateway (exclusive / parallel / inclusive) if / fork / switch
Sequence flow --> or implicit
Pool / lane `
Sub-process partition X { ... } or note right of
Event (start / end / intermediate) start / stop / (*)
Message flow :send msg; + sync -->

For non-strict workflows, activity is enough. For strict BPMN, use Camunda Modeler (or similar) and render back through PlantUML.

TL;DR

Activity diagrams are underused in PlantUML — fork/join/partition/exception support is real. Draw the flow first, the sequence diagram second; together they make a complete business document.

  • Title: PlantUML activity diagrams: branching to concurrent
  • Author: puml.online
  • Created at : 2026-07-29 15:05:00
  • Updated at : 2026-08-14 21:34:29
  • Link: https://puml.online/blog/plantuml-activity-diagram-en/
  • License: This work is licensed under CC BY-NC-SA 4.0.