How to Diagram a State Machine
Any object that moves through defined states - an order, a subscription, a document - is a state machine hiding in your code. Drawing it makes the illegal transitions obvious before a bug allows one.
A surprising amount of software is really a state machine wearing other clothes. An order is created, paid, shipped, delivered, or cancelled. A subscription is trialing, active, past-due, or cancelled. A document is draft, in review, published, or archived. Each of these is an object that occupies exactly one state at a time and moves between states in response to events, following rules about which moves are allowed. When those rules live only in scattered conditionals, illegal transitions slip through - a delivered order getting cancelled, a cancelled subscription getting charged.
This guide shows how to diagram a state machine so the legal states, the events that cause transitions, and the moves that must never happen are all explicit. A UML state diagram is the natural format, and you can draw one in Atlas Diagram Studio at /diagrams or generate a first draft from a description with the AI diagram generator at /diagram-tools/ai-diagram-generator. The worked example is the lifecycle of an order, which most software people can reason about immediately.
States, transitions, events, and guards
A state machine diagram has four building blocks. States are the distinct conditions the object can be in, drawn as rounded boxes - Created, Paid, Shipped. Transitions are the arrows between states, showing an allowed move. Events are the triggers that cause a transition, labeling the arrow - the "payment received" event moves an order from Created to Paid. Guards are conditions that must hold for a transition to fire, written in brackets, so an arrow might read "cancel [only if not yet shipped]."
Two special markers complete the picture. An initial state, shown as a filled dot with an arrow, marks where an object begins its life - an order starts in Created. Final states, shown as a dot in a ring, mark where the lifecycle ends - Delivered or Cancelled. With these building blocks you can express any lifecycle precisely, and the discipline of drawing them forces you to decide exactly which events are valid in each state rather than discovering the answer through bugs.
A worked example: the order lifecycle
Model an order. It begins in Created. A "payment received" event transitions it to Paid. A "shipped" event moves it from Paid to Shipped, and a "delivered" event moves it from Shipped to Delivered, which is a final state. So far it is a simple chain, but the interesting rules are about cancellation and failure. A "cancel" event can move the order from Created or Paid to Cancelled, another final state - but crucially, it should not be allowed once the order is Shipped, which is a guard the diagram makes explicit.
Now add the realistic branches. From Created, a "payment failed" event might loop back to Created or move to a Payment Failed state that allows a retry. From Paid, a refund could transition to a Refunded final state. Drawing all of this reveals questions that code often leaves ambiguous: can a Shipped order be cancelled, what happens to payment when it is, and is Refunded distinct from Cancelled. Each answer becomes a transition, a guard, or a deliberately absent arrow, and the diagram becomes a specification the implementation can be checked against.
What a good state diagram includes
A state machine diagram is only as useful as the rules it makes explicit. Include these elements.
- Every legal state, named clearly and distinct - no vague catch-all state that hides several real conditions.
- The initial state, so it is unambiguous where an object begins its life.
- One or more final states, marking where the lifecycle legitimately ends.
- Every valid transition as an arrow, labeled with the event that triggers it.
- Guards in brackets where a transition is only allowed under a condition.
- Actions or side effects on transitions where relevant, such as sending a confirmation when entering Shipped.
- The invalid transitions you care about - either by their deliberate absence or an explicit note - so illegal moves are visibly disallowed.
Making illegal transitions impossible
The deepest value of a state diagram is negative space: the transitions that are not drawn are the ones that must never happen. If there is no arrow from Delivered to Cancelled, then cancelling a delivered order is illegal by design, and your implementation should reject it. This is where diagramming pays for itself, because the diagram becomes a checklist for the code - every allowed transition should be implemented, and every disallowed one should be actively refused rather than silently permitted by a missing check.
Turning the diagram into robust code is then mechanical. The states become an enumeration, the transitions become the only permitted moves, and any attempt to transition outside the diagram is an error. This is exactly how you prevent the class of bugs where an object ends up in an impossible combination of conditions. Build the state machine in Atlas Diagram Studio at /diagrams and keep it as the reference for the object's behavior; share it for review so everyone agrees on the rules. For the wider modeling context, see the guide on when to use each UML diagram type and the complete UML guide.