Skip to main content

State Machine Diagram

Overview​

A state machine diagram is a behavioural UML diagram. It describes the life cycle of a single object, component or system: which states it can be in, which events move it from one state to the next, and what happens on the way.

Typical applications:

  • Order status in a shop system (New, Paid, Shipped, Delivered, Cancelled)
  • Session or login handling (Anonymous, Authenticated, Locked, Expired)
  • Device and connection states (Off, Booting, Ready, Error)
  • Protocol and parser logic, where the next character is interpreted differently depending on the state
  • The internal behaviour of a class whose methods are only allowed in certain states

Notation​

ElementNotationMeaning
Initial pseudostateFilled circle ●Where the life cycle begins, exactly one per region
StateRounded rectangle with a nameA situation in which the object waits, named as an adjective or a noun
TransitionArrow from one state to anotherState change, labelled trigger [guard] / effect, every part optional
TriggerEvent name on the transitionThe event that offers the transition, e.g. cancel, timeout
Completion transitionTransition without a triggerFires as soon as the behaviour of the source state is finished
Guard[condition] on the transitionBoolean condition, the transition only fires if it evaluates to true
Effect/ action on the transitionAction executed while the transition fires, it must not block
Self-transitionArrow leaving and re-entering the same stateThe state is left and entered again, exit and entry do run
Internal transitiontrigger / effect inside the state boxReaction without a state change, exit and entry do not run
Entry activityentry / action inside the state boxRuns every time the state is entered, regardless of the transition used
Do activitydo / activity inside the state boxRuns continuously while the state is active, may be interrupted
Exit activityexit / action inside the state boxRuns every time the state is left, regardless of the transition used
Composite stateState box containing further statesA state broken down into substates
RegionPart of a composite state, separated by a dashed lineSubstates that are active at the same time
ChoiceDiamond on a transitionBranch evaluated after the effect, outgoing transitions carry guards
Shallow historyCircle containing HOn re-entry, the substate last active in that composite state is resumed
Deep historyCircle containing H*Resumes the last active substate including all nested levels
Final stateFilled circle in a ring ◉The life cycle ends here, the object accepts no further events

Naming rules that keep a diagram readable:

  • States describe a condition, not an activity: Paid, Waiting for payment, not Pay
  • Triggers are named after the event, not after the method that handles it: cancel, not handleCancel
  • Effects and internal activities are named as operations with brackets: / refundPayment()

Building Blocks​

States and Transitions​

●
│
▼
╭────────────────────────╮
│ Idle │
╰────────────────────────╯
│
│ coinInserted [amount >= price] / unlock()
▼
╭────────────────────────╮
│ Ready │
╰────────────────────────╯
│
│ productSelected / dispense()
▼
◉

Read as a sentence: in state Idle, when the event coinInserted occurs and the condition amount >= price holds, unlock() is executed and the machine changes to Ready. If the event occurs but the guard is false, the event is discarded and the state does not change.

Self-Transition​

After a self-transition the object is in the same state as before. On the way, the state is left and entered again, so exit and entry run and a do activity is restarted.

┌───────────────────────────────────┐
│ digitPressed / appendDigit() │
│ │
│ ╭───────────────────────────╮ │
└──►│ Collecting │───┘
╰───────────────────────────╯

If restarting entry, do and exit is undesirable, an internal transition is used instead. It is written inside the state box and leaves the state active:

╭───────────────────────────────────────────╮
│ Collecting │
├───────────────────────────────────────────┤
│ digitPressed / appendDigit() │
╰───────────────────────────────────────────╯

For example, a timeout implemented as entry / startTimer() is reset by a self-transition and kept running by an internal transition.

Internal Activities​

Three keywords describe behaviour that belongs to the state itself rather than to a transition:

  • entry / action: executed once on every entry, before any do activity
  • do / activity: executed while the state is active, may run for a long time and may be interrupted by an outgoing transition
  • exit / action: executed once on every exit, after the do activity has ended or been aborted
╭───────────────────────────────────────────╮
│ Heating │
├───────────────────────────────────────────┤
│ entry / switchHeaterOn() │
│ do / measureTemperature() │
│ exit / switchHeaterOff() │
╰───────────────────────────────────────────╯

The order for a state change is always: exit of the source state, then the effect of the transition, then entry of the target state.

Putting an action into entry instead of onto every incoming transition removes duplication and guarantees that the action cannot be forgotten when a new transition into that state is added later.

Composite States​

A composite state contains a state machine of its own. It keeps diagrams small and allows a transition to be drawn once for a whole group of substates.

╭────────────────────────────────────────────────────────╮
│ Active │
│ │
│ ● │
│ │ │
│ ▼ │
│ ╭───────────────────╮ connected ╭───────────────────╮
│ │ Dialling │────────────►│ Talking │
│ ╰───────────────────╯ ╰───────────────────╯
│ │
╰────────────────────────────────────────────────────────╯
│
│ hangUp
▼
╭───────────────────╮
│ Idle │
╰───────────────────╯

The transition hangUp starts at the border of the composite state, so it applies to Dialling and Talking alike.

Rules worth keeping in mind:

  • A composite state needs its own initial pseudostate, otherwise it is undefined which substate becomes active
  • Exactly one substate is active at a time per region, together with the composite state that contains it
  • A transition may also point directly at a substate, which bypasses the initial pseudostate
  • A final state inside a composite state ends that inner machine, which then triggers the outgoing completion transition of the composite state

Regions and Parallel States​

A composite state may be divided into regions by a dashed line. Each region has its own initial pseudostate, substates and transitions. While the composite state is active, one substate is active in every region at the same time. This models independent aspects of one object, such as audio and video of a recording.

╭──────────────────────────────────────────────────────────╮
│ Recording │
│ │
│ ● │
│ │ │
│ ▼ │
│ ╭───────────────╮ muteAudio ╭───────────────╮ │
│ │ AudioRunning │──────────────►│ AudioMuted │ │
│ ╰───────────────╯ ╰───────────────╯ │
│ │
│ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │
│ │
│ ● │
│ │ │
│ ▼ │
│ ╭───────────────╮ pauseVideo ╭───────────────╮ │
│ │ VideoRunning │──────────────►│ VideoPaused │ │
│ ╰───────────────╯ ╰───────────────╯ │
│ │
╰──────────────────────────────────────────────────────────╯

An event is offered to every region. It may trigger a transition in one region, in several regions or in none.

History State​

A history state answers the question where does the machine continue after an interruption. Without it, re-entering a composite state always starts at its initial pseudostate.

╭──────────────────────────────────────────╮
│ Playing │
resume │ │
┌───────────►│ (H) │
│ │ │ │
│ │ ▼ │
│ │ ╭───────────╮ ╭───────────╮ │
│ │ │ Track 1 │───────►│ Track 2 │ │
│ │ ╰───────────╯ ╰───────────╯ │
│ ╰──────────────────────────────────────────╯
│ │ pause
│ ╭──────────────▼───────────╮
└────────────│ Paused │
╰──────────────────────────╯

The shallow history (H) restores the substate that was last active on this level. A deep history (H*) restores the last configuration including all nested levels. If the composite state has never been entered before, the transition into the history state falls back to the initial pseudostate.


State Transition Table​

A state machine diagram can also be written as a state transition table. The table is easier to check for completeness than the diagram, because missing combinations of state and event stand out when the rows are grouped by state.

Current stateEventGuardEffectNext state
NewitemAdded–recalculateTotal()–
NewpaymentReceived–capturePayment()Paid
Newcancel–releaseReservation()Cancelled
PaiddispatchedallItemsInStocksendTrackingMail()Shipped
Paidcancel–refundPayment()Cancelled
Shippeddelivered––Delivered

A combination that does not appear in the table triggers no transition. The event is discarded without effect.

A row with an empty Next state column and a filled Effect column describes an internal transition. A row whose current state and next state are identical describes a self-transition.


Example: Order Status​

The life cycle of an order in a shop system, from creation to delivery or cancellation.

●
│
▼
╭────────────────────────╮
│ New │
│ entry / reserveItems() │
╰────────────────────────╯
│ │
paymentReceived │ │ cancel
/ capturePayment() │ / releaseReservation()
┌───────────┘ └────────────┐
▼ │
╭────────────────────────╮ │
│ Paid │──────────────────────►┤
╰────────────────────────╯ cancel │
│ / refundPayment() │
│ dispatched [allItemsInStock] │
│ / sendTrackingMail() ▼
▼ ╭────────────────────────╮
╭────────────────────────╮ │ Cancelled │
│ Shipped │ ╰────────────────────────╯
╰────────────────────────╯ │
│ │
│ delivered │
▼ │
╭────────────────────────╮ │
│ Delivered │ │
╰────────────────────────╯ │
│ │
└───────────────────┐ ┌───────────────┘
▼ ▼
◉

What we can learn from this example:

  • The refund sits on the transition Paid => Cancelled and not as an entry activity of Cancelled, because an order cancelled from New has never been paid.
  • dispatched carries a guard. If stock is missing, the order stays in Paid.
  • Shipped has no transition for cancel. The business rule a dispatched order can no longer be cancelled is expressed by the absence of a transition.

Implemented in code, each state becomes a value of an enumeration, and the table becomes a switch over state and event. Everything not listed in the table falls into the default branch and is rejected. An invalid state change is therefore impossible by construction.


Delimitation from the Activity Diagram​

AspectState machine diagramActivity diagram
NodeA state, the object waitsAn action, work is being done
NamingAdjective or noun: PaidVerb + object: Capture payment
ArrowTriggered by an eventFires when the previous action is finished
ScopeThe life cycle of one objectOne process run, possibly across several actors
BranchGuards on outgoing transitionsDecision node with guarded flows
ParallelismRegions inside a composite stateFork and join
Typical questionWhich state is the order in?Which step comes next?

If an arrow can only be labelled with something like afterwards, an activity diagram is the right choice. If the arrow needs a name such as cancel, timeout or paymentReceived, a state machine diagram fits.


Common Mistakes​

  1. Activities used as state names: Pay is an action and belongs in an activity diagram. The state is Paid or Waiting for payment.
  2. Transitions without a trigger: an arrow between two states without an event is a completion transition. It fires as soon as the source state has finished its behaviour.
  3. Overlapping guards: if two transitions with the same trigger can both have a true guard, the behaviour is undefined. The guards must exclude each other.
  4. Guard confused with trigger: [cancel] is a condition, not an event. cancel [orderNotShipped] separates the two correctly.
  5. Missing initial pseudostate: without it, the starting state is undefined. Every diagram and every region needs exactly one.
  6. Unreachable or dead-end states: a state without an incoming transition is never reached. A state without an outgoing transition that is not a final state traps the object.
  7. Self-transition where an internal transition is meant: a self-transition restarts entry, do and exit. A timer started in entry is reset as a result.
  8. State explosion: combining independent aspects into one flat set of states multiplies the number of states. Regions or additional attributes avoid this.

Tools​

  • draw.io / diagrams.net (free, browser-based, UML shape library included)
  • PlantUML (text-based, diagram is generated from source and can be versioned)
  • Mermaid (text-based, stateDiagram-v2 renders directly in Markdown on many platforms)
  • Visual Paradigm, StarUML, Lucidchart (commercial, with free tiers)

See Also​