State Diagrams
State diagrams show how a machine transitions between states. They're ideal for technical documentation and understanding machine logic.
What State Diagrams Show
- States as boxes or circles
- Transitions as arrows between states
- Events as labels on transitions
- Guards as conditions on transitions
How States Are Derived
States in EventFlow are not arbitrary labels—they are derived from wait points in the lane diagram. Before diving into state diagrams, it's important to understand where states come from.
The Core Insight: STATE = WAIT POINT
A state exists only when the system is waiting:
- Waiting for external input → Creates an intermediate state
- Process complete (success/failure) → Creates a terminal state
This means you don't invent states during design sessions. Instead, you:
- Create lane diagrams first (Sessions 1-2 with full team)
- Identify wait points where the system pauses for external events
- Derive states from those wait points (Session 4, developer only)
States are defined explicitly in your flow file using the moves to #state syntax.
Basic Example
From this EventFlow:
machine: @order
scenario: order lifecycle
on :checkout from @customer (api)
order moves to #awaiting_payment
on :payment_success from @payment
order moves to #paid
on :payment_failed from @payment
order moves to #payment_failed
on :ship from @warehouse
order moves to #shippedGenerates:
State Types
Initial State
The first state when a machine instance is created:
Final States
States with no outgoing transitions:
Intermediate States
States with both incoming and outgoing transitions:
Transitions with Guards
When transitions have conditions:
on :approve from @manager
? amount < 1000
order moves to #approved
? amount >= 1000
order moves to #needs_director_approvalSelf-Transitions
When an event keeps the machine in the same state:
on :retry from @system
? attempts < 3
$attempts increases by 1
// stays in #processingComplex State Machines
Order Lifecycle
Branching and Merging
Branching
Merging
Reading State Diagrams
Follow the Flow
- Start at the initial state (○ or the first state)
- Follow arrows labeled with events
- Note guards in brackets [condition]
- End at final states (states with no outgoing arrows)
Identify Paths
- Happy path: The expected successful flow
- Error paths: Flows that lead to error/failure states
- Recovery paths: Flows from error states back to normal flow
Use Cases
Technical Documentation
Include state diagrams in technical docs:
eventflow diagram order.flow --type=state --format=svgCode Reviews
Visualize changes to state machine logic:
# Compare diagrams before/after changes
eventflow diagram order.flow --type=state > after.svg
git show HEAD~1:order.flow | eventflow diagram --type=state > before.svgDebugging
Trace through states to understand behavior:
eventflow diagram order.flow --type=state --highlight-path="checkout,payment_success,ship"Best Practices
Derive, Don't Invent
States should be derived from wait points, not arbitrarily invented:
// Good - corresponds to wait points
#awaiting_payment // Waiting for :payment_success or :payment_failed
#pending_approval // Waiting for :approve or :reject
#confirmed // Terminal: process complete
// Avoid - doesn't correspond to waiting
#processing // What is it waiting for?
#step_2 // Arbitrary label
#in_progress // Too vagueWhen you find yourself creating a state, ask: "What external event is the system waiting for?" If there's no clear answer, the state may not be necessary.
States are defined explicitly using moves to #state syntax in your event handlers.
Keep States Focused
Each state should represent a clear, distinct condition:
// Good - clear states
#draft
#pending_review
#approved
#rejected
// Avoid - vague states
#state1
#processing
#doneName Transitions Clearly
Events on transitions should explain what triggers the change:
// Good - clear transitions
:submit_for_review
:approve_order
:reject_with_reason
// Avoid - unclear
:next
:do
:okDocument Terminal States
Make it clear which states are final: