Modeling workflows with Mermaid state diagrams
Every system that tracks status is hiding a state machine. Order management, user onboarding, approval queues, CI pipelines — they all move objects through a defined set of states via transitions. The problem is that this logic usually lives scattered across conditional branches in your code, implicit in column values in your database, and memorized by the one engineer who wrote the feature.
Mermaid's stateDiagram-v2 makes that implicit model explicit. The diagram is plain text, lives next to your code, and updates in the same pull request as the transition logic it describes.
What a state diagram shows
A state diagram has three building blocks:
- States — the possible statuses an object can be in (
Pending,Active,Cancelled) - Transitions — the events or actions that move an object from one state to another
- Forks and joins — for parallel workflows where multiple branches run simultaneously
Every stateDiagram-v2 has two implicit special states: [*] is the entry point (start), and [*] as a transition target is the exit point (terminal state).
Syntax in 60 seconds
stateDiagram-v2
[*] --> Draft
Draft --> Submitted : submit()
Submitted --> UnderReview : assign()
UnderReview --> Approved : approve()
UnderReview --> Rejected : reject()
Approved --> [*]
Rejected --> Draft : revise()
Read each line as: from state, to state, on event. A rejected submission goes back to Draft for revision; an approved one reaches the terminal state. The whole lifecycle fits in seven lines.
A real-world example: e-commerce order lifecycle
Most order systems have around eight states. Here's a complete lifecycle with a cancellation path:
stateDiagram-v2
[*] --> Placed
Placed --> PaymentPending : initiate_payment()
PaymentPending --> Confirmed : payment_succeeded()
PaymentPending --> Cancelled : payment_failed()
Confirmed --> Processing : warehouse_accepted()
Processing --> Shipped : dispatch()
Shipped --> Delivered : delivery_confirmed()
Delivered --> [*]
Placed --> Cancelled : cancel()
Confirmed --> Cancelled : cancel()
Cancelled --> [*]
Compare this to hunting through a status enum, a handful of database triggers, and three separate webhook handlers to assemble the same picture. The diagram doesn't replace those artifacts — it maps how they fit together.
Nested states for complex sub-flows
Some states contain their own internal logic. stateDiagram-v2 supports nested state blocks, which keeps the top-level diagram readable while preserving detail for the states that need it:
stateDiagram-v2
[*] --> Onboarding
state Onboarding {
[*] --> EmailVerification
EmailVerification --> ProfileSetup : email_verified()
ProfileSetup --> TeamInvite : profile_saved()
TeamInvite --> [*]
}
Onboarding --> Active : onboarding_complete()
Active --> Suspended : suspend()
Suspended --> Active : reactivate()
Active --> Deleted : delete()
Deleted --> [*]
The user's onboarding sub-flow is self-contained. Anyone reading the top-level diagram knows what Active means without needing to see the internal steps — but those steps are still there when needed.
Parallel states with forks
When a workflow splits into independent concurrent tracks, use the fork / join construct to make the parallelism explicit:
stateDiagram-v2
[*] --> Processing
state Processing {
[*] --> fork_state
state fork_state <<fork>>
fork_state --> InventoryCheck
fork_state --> FraudCheck
state join_state <<join>>
InventoryCheck --> join_state
FraudCheck --> join_state
join_state --> [*]
}
Processing --> ReadyToShip : all_checks_passed()
Processing --> OnHold : any_check_failed()
The fork and join make it unambiguous that inventory and fraud checks run in parallel and both must complete before the order moves on.
Notes and descriptions
Add a note to a state to surface context that can't be expressed as a transition label:
stateDiagram-v2
[*] --> Pending
Pending --> Active : activate()
Active --> Expired : ttl_elapsed()
Expired --> [*]
note right of Pending
Created when user
completes checkout.
TTL: 15 minutes.
end note
Notes are especially useful in diagrams shared with non-engineers — they replace a paragraph of inline comments with a label attached to exactly the right state.
Where state diagrams earn their keep
Code review. Paste a state diagram into a PR description when you're adding or changing a transition. Reviewers see the full lifecycle at once instead of tracing conditionals across multiple files.
Incident postmortems. "The order got stuck in Processing because the join never fired" is a sentence that makes sense to everyone when there's a diagram to point at.
Onboarding documentation. New engineers learn a domain model in minutes from a state diagram. They spend hours tracing the equivalent code path.
Specification first. Sketch the states before writing the code. Edge cases like "can a Shipped order be Cancelled?" surface naturally when you try to draw the transition and realize you don't have an answer.
State diagrams vs. flowcharts
Flowcharts and state diagrams look similar but model different things. A flowchart documents a process — the steps a human or system performs in sequence. A state diagram documents the lifecycle of an object — the statuses it can hold and the events that change them.
If you're mapping "what does the checkout function do step by step," use a flowchart. If you're mapping "what states can an order be in," use a state diagram. Getting this distinction right makes both diagrams sharper.
Rule of thumb: if your diagram has rectangles labeled with verbs, it's a flowchart. If it has rounded nodes labeled with nouns, it's a state machine.
Draw the state machine before you write the migration that adds the status column. By the time the PR is open, the whole team already understands what the column means.
Related posts
Common Mermaid diagram errors and how to fix them fast
Syntax errors, rendering glitches, and layout surprises break diagramming workflows. Learn to spot and fix the 10 most common Mermaid mistakes before they slow you down.
Flowchart vs sequence diagram: when to use each in Mermaid
Both show process flows, but flowcharts model decisions and branches while sequence diagrams trace interactions over time. Here's how to pick the right one.