Skip to main content

Activity diagram

What happens, step by step, including every branch? A flowchart, formalized: rounded start and end markers, rectangles for actions, diamonds for decisions, and (once the process needs it) bars for genuine parallelism. No participants, no lifelines, no messages between objects - just the process itself, told as a sequence of steps.

Initial and final nodes

Every activity diagram starts at exactly one initial node - a small filled circle - and ends at one or more activity final nodes - a circle with a ring around it. Between them sit the actions and decisions that make up the process.

Do the work
Filled circle starts it. Ringed circle ends it. Everything else sits between the two.

Actions, decisions, and merges

An action is a rounded rectangle - one step of work, named as a verb phrase. A decision node is a diamond with one path in and several paths out, each labeled with a [guard]; exactly one guard is true on any given run, so exactly one outgoing path fires. A merge node is a decision node's mirror image: several paths in, one path out, reuniting branches that a decision node split earlier.

Valid?[yes]Continue[no]Show errormerge
One diamond splits the flow by a guard; a second diamond, drawn the same way, brings the branches back together.

Nothing in the notation distinguishes a decision diamond from a merge diamond visually - the difference is entirely in how many arrows go in versus out.

Fork and join bars

A fork is a thick black bar with one incoming path and several outgoing ones that all start concurrently - unlike a decision node, there is no guard choosing between them, every branch fires. A join is the mirror bar: several concurrent paths in, and the flow does not continue past it until all of them have finished.

Send EmailWrite Audit LogRespond to user
The fork bar starts both branches at once. The join bar waits for both before letting the flow continue.

Guards on transitions

A guard is a bracketed boolean condition written next to an arrow, restricting when that arrow may be followed - [amount > 100], [credentials valid]. Guards are what make a decision node's branches mutually exclusive rather than ambiguous: every path out of a decision node needs its own guard, and the set of guards should cover every case the diamond can actually produce.

Swimlanes (partitions)

A swimlane (or partition) divides the diagram into vertical or horizontal bands, one per actor or component, and places every action inside whichever lane is responsible for it. The flow logic - decisions, forks, guards - works exactly the same; a swimlane only adds "who does this step" on top of "what happens next."

CustomerRestaurantPlace orderPrepare foodNotify readyPick up order
Same flow as any other activity diagram - the lane boundary just makes "whose job is this step" a drawn fact.

The login flow, built up in stages

Stage 1 - the straight path with one decision. Enter credentials, check them, branch.

Enter credentialsValid?[yes]Redirect[no]Show error

Stage 2 - merge the branches, add fork/join for the side-effects. A successful login fires two independent, concurrent actions - send a "new login" notification and write an audit log entry - and both must finish before the response goes back.

Enter credentialsValid?[no]Show error[yes]Send NotificationWrite Audit Log
The error path and the join-then-end path are two separate ways to reach the same final node - a diagram can have more than one route to "done."

When to reach for it: a business process or workflow with real branching - an approval chain, an order pipeline with a refund path, anything with more than one decision diamond worth drawing. When not to bother: a single method's control flow. if (x) return a; else return b; is not worth a flowchart - that is what the code itself is for.

Common mistakes

  • Using a fork where a decision was meant. A fork runs every outgoing branch; a decision runs exactly one. Drawing a fork for "either do A or do B" describes both happening at once, which is very rarely what was intended.
  • Missing guards on a decision's branches, or guards that overlap. Every path out of a diamond needs its own [condition], and the conditions should be mutually exclusive and exhaustive - otherwise the diagram is silent (or ambiguous) about what happens in the gap.
  • Forgetting the join. A fork with no matching join implies the concurrent branches never need to be waited on, which is rarely true - if the flow continues past both, draw the join bar to say so explicitly.
  • Cramming everything into one swimlane. If every action lives in the same lane, the swimlanes are not adding information - only introduce them once responsibility for steps genuinely crosses actor or component boundaries.

Try it yourself: sketch an activity diagram for placing a food-delivery order with two swimlanes, Customer and Restaurant. Where does a decision diamond belong (is the restaurant currently accepting orders)? Where would a fork/join pair make sense (charging the card and reserving inventory at the same time)?

Check yourself

Question 1 of 4

A flowchart has a filled black circle at the top and a ringed (bullseye) circle at the bottom. What do these mark?