Skip to content

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

Basic Example

From this EventFlow:

flow
machine: @order

scenario: order lifecycle

  on> :checkout from @customer
    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 #shipped

Generates:

                        @order

    ┌───────────────────────────────────────────────┐
    │                                               │
    │  ┌─────────┐                                  │
    │  │ (start) │                                  │
    │  └────┬────┘                                  │
    │       │                                       │
    │       │ :checkout                             │
    │       ▼                                       │
    │  ┌────────────────────┐                       │
    │  │ #awaiting_payment  │                       │
    │  └────────┬───────────┘                       │
    │           │                                   │
    │     ┌─────┴─────┐                             │
    │     │           │                             │
    │ :payment_   :payment_                         │
    │ success     failed                            │
    │     │           │                             │
    │     ▼           ▼                             │
    │ ┌───────┐  ┌────────────────┐                 │
    │ │ #paid │  │ #payment_failed│                 │
    │ └───┬───┘  └────────────────┘                 │
    │     │                                         │
    │     │ :ship                                   │
    │     ▼                                         │
    │ ┌──────────┐                                  │
    │ │ #shipped │                                  │
    │ └──────────┘                                  │
    │                                               │
    └───────────────────────────────────────────────┘

    ─── = transition
    ▼   = direction

State Types

Initial State

The first state when a machine instance is created:

    ○ (initial)

    │ :create

┌─────────┐
│ #draft  │
└─────────┘

Final States

States with no outgoing transitions:

┌───────────┐
│ #completed│  ← Final state
└───────────┘

┌───────────┐
│ #cancelled│  ← Final state
└───────────┘

Intermediate States

States with both incoming and outgoing transitions:



    ┌─────────┐
    │#pending │  ← Intermediate
    └────┬────┘

Transitions with Guards

When transitions have conditions:

flow
on :approve from @manager
  ? amount < 1000
    order moves to #approved
  ? amount >= 1000
    order moves to #needs_director_approval
    ┌───────────┐
    │ #pending  │
    └─────┬─────┘

    ┌─────┴──────┐
    │            │
[<1000]      [>=1000]
    │            │
    ▼            ▼
┌─────────┐  ┌──────────────────────┐
│#approved│  │#needs_director_approval│
└─────────┘  └──────────────────────┘

Self-Transitions

When an event keeps the machine in the same state:

flow
on :retry from @system
  ? attempts < 3
    $attempts increases by 1
    // stays in #processing
    ┌─────────────┐
    │ #processing │◀─┐
    └─────────────┘  │
          │          │
          └── :retry ┘
           [attempts < 3]

Complex State Machines

Order Lifecycle

                           @order

┌─────────────────────────────────────────────────────────────┐
│                                                             │
│  ┌──────┐   :add_item   ┌─────────┐  :checkout  ┌─────────┐ │
│  │#empty│──────────────>│ #cart   │────────────>│#checkout│ │
│  └──────┘               └────┬────┘             └────┬────┘ │
│                              │                       │      │
│                         :clear                  :submit     │
│                              │                       │      │
│                              ▼                       ▼      │
│                         ┌──────┐              ┌──────────┐  │
│                         │#empty│              │#submitted│  │
│                         └──────┘              └────┬─────┘  │
│                                                    │        │
│                              ┌─────────────────────┤        │
│                              │                     │        │
│                         :approve              :reject       │
│                              │                     │        │
│                              ▼                     ▼        │
│                        ┌──────────┐        ┌──────────┐     │
│                        │#approved │        │#rejected │     │
│                        └────┬─────┘        └──────────┘     │
│                             │                               │
│                        :ship                                │
│                             │                               │
│                             ▼                               │
│                       ┌──────────┐                          │
│                       │#shipped  │                          │
│                       └────┬─────┘                          │
│                            │                                │
│                       :deliver                              │
│                            │                                │
│                            ▼                                │
│                      ┌───────────┐                          │
│                      │#delivered │                          │
│                      └───────────┘                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Branching and Merging

Branching

         ┌─────────┐
         │#pending │
         └────┬────┘

        ┌─────┼─────┐
        │     │     │
   :approve :reject :cancel
        │     │     │
        ▼     ▼     ▼

Merging

   ┌──────────┐  ┌──────────┐
   │#approved │  │#fast_track│
   └────┬─────┘  └─────┬────┘
        │              │
        └──────┬───────┘

          :process


        ┌──────────┐
        │#completed│
        └──────────┘

Reading State Diagrams

Follow the Flow

  1. Start at the initial state (○ or the first state)
  2. Follow arrows labeled with events
  3. Note guards in brackets [condition]
  4. 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:

bash
eventflow diagram order.flow --type=state --format=svg

Code Reviews

Visualize changes to state machine logic:

bash
# Compare diagrams before/after changes
eventflow diagram order.flow --type=state > after.svg
git show HEAD~1:order.flow | eventflow diagram --type=state > before.svg

Debugging

Trace through states to understand behavior:

bash
eventflow diagram order.flow --type=state --highlight-path="checkout,payment_success,ship"

Best Practices

Keep States Focused

Each state should represent a clear, distinct condition:

flow
// Good - clear states
#draft
#pending_review
#approved
#rejected

// Avoid - vague states
#state1
#processing
#done

Name Transitions Clearly

Events on transitions should explain what triggers the change:

flow
// Good - clear transitions
:submit_for_review
:approve_order
:reject_with_reason

// Avoid - unclear
:next
:do
:ok

Document Terminal States

Make it clear which states are final:

┌───────────────┐
│  #completed   │  ← Success final state
│   (final)     │
└───────────────┘

┌───────────────┐
│  #cancelled   │  ← Failure final state
│   (final)     │
└───────────────┘

Released under the MIT License.