Free · No sign-up · Works with .mmd files

Mermaid state diagram editor

A state diagram shows the states a single thing can be in and the events that move it between them. Use one when the subject is a lifecycle — an order, a subscription, a document under review. The giveaway is that your labels are adjectives rather than verbs: pending, shipped, cancelled.

An order lifecycle with a terminal cancellation

The states are what an order is; the labels on the arrows are what happened to it. Note that Cancelled is reachable from three states but leads nowhere — that asymmetry is exactly the kind of thing a state diagram makes obvious and a flowchart hides.

stateDiagram-v2
    [*] --> Pending: order placed
    Pending --> Paid: payment captured
    Pending --> Cancelled: customer cancels
    Paid --> Packed: warehouse picks
    Paid --> Refunded: payment reversed
    Packed --> Shipped: carrier collects
    Packed --> Cancelled: stock missing
    Shipped --> Delivered: carrier confirms
    Shipped --> Lost: no scan for 14 days
    Delivered --> [*]
    Refunded --> [*]
    Cancelled --> [*]
    Lost --> Refunded: claim approved
Open this in the editor
Advertisement

Worked examples

1. The minimum state machine

`[*]` is both the start and the end pseudo-state — which one it means depends on which side of the arrow it sits.

stateDiagram-v2
    [*] --> Draft
    Draft --> Published: publish
    Published --> [*]
Open in the editor

2. Naming states that contain spaces

State ids cannot contain spaces, but `state "Label" as id` gives you a readable label with a safe id. This is the state-diagram equivalent of a quoted flowchart label.

stateDiagram-v2
    state "Awaiting review" as review
    state "Changes requested" as changes
    [*] --> review
    review --> changes: reviewer objects
    changes --> review: author pushes fix
    review --> [*]: approved
Open in the editor

3. Composite states

A state can contain its own state machine. Use this when a stage has meaningful internal steps that would otherwise clutter the top level — here, everything that happens inside Processing.

stateDiagram-v2
    [*] --> Queued
    Queued --> Processing: worker picks up

    state Processing {
        [*] --> Validating
        Validating --> Transforming: schema ok
        Transforming --> Writing: rows mapped
        Writing --> [*]
    }

    Processing --> Succeeded: no errors
    Processing --> Failed: exception thrown
    Failed --> Queued: retry
    Succeeded --> [*]
Open in the editor

4. Choice pseudo-states

A `<<choice>>` is a branch that depends on a condition rather than an event. It keeps the decision visible without pretending it is a state the object rests in.

stateDiagram-v2
    state check <<choice>>
    [*] --> Submitted
    Submitted --> check: run risk scoring
    check --> Approved: score < 40
    check --> ManualReview: score >= 40
    ManualReview --> Approved: analyst accepts
    ManualReview --> Rejected: analyst declines
    Approved --> [*]
    Rejected --> [*]
Open in the editor

5. Concurrent regions

Two dashes on their own line split a composite state into regions that are active at the same time. This is the one thing a state diagram does that a flowchart genuinely cannot.

stateDiagram-v2
    [*] --> Onboarding

    state Onboarding {
        [*] --> EmailUnverified
        EmailUnverified --> EmailVerified: link clicked
        --
        [*] --> ProfileEmpty
        ProfileEmpty --> ProfileComplete: form submitted
    }

    Onboarding --> Active: both complete
    Active --> [*]
Open in the editor

State diagram syntax reference

Use `stateDiagram-v2` rather than `stateDiagram`. Both render, but v2 is the actively developed layout engine and handles composite and concurrent states far better.

SyntaxMeaning
stateDiagram-v2Opens the diagram. `stateDiagram` still works but is the older layout.
[*] --> AInitial state — the entry point.
A --> [*]Terminal state.
A --> BTransition with no trigger named.
A --> B: eventTransition labelled with the event that causes it.
state "Label" as idReadable label with a space-free id.
state A { ... }Composite state containing its own machine.
--Inside a composite state, splits it into concurrent regions.
state x <<choice>>Condition-based branch point.
state f <<fork>> / <<join>>Split into and merge from parallel transitions.
note right of A: textAttach a note. Also `note left of`.
direction LRLay the machine out left-to-right instead of top-down.
Advertisement

Six errors that actually break state diagrams

Reproduced against Mermaid 11.12.2. The first four stop the diagram rendering. The last two are worse: they render happily and give you a diagram that does not mean what you wrote.

What you see

Parse error, ending in: got 'INVALID'

Why

A hyphen in a state id. Kebab-case names are natural to reach for — in-progress, pre-approved — but the hyphen is read as the start of a transition arrow.

Fix

Use a single word or underscores for the id, and put the readable text in a quoted label.

Broken
stateDiagram-v2
    [*] --> in-progress
    in-progress --> Done
Fixed
stateDiagram-v2
    state "In progress" as inProgress
    [*] --> inProgress
    inProgress --> Done

What you see

Parse error inside a composite state

Why

A composite state opened with `{` and never closed. The closing brace has to be on its own line.

Fix

Close the block.

Broken
stateDiagram-v2
    [*] --> Outer
    state Outer {
        [*] --> Inner
Fixed
stateDiagram-v2
    [*] --> Outer
    state Outer {
        [*] --> Inner
    }

What you see

Lexical error on line N. Unrecognized text.

Why

The concurrent-region separator written with the wrong number of dashes. It is exactly two, on their own line, inside a composite state. Three dashes is a different token entirely.

Fix

Use exactly `--`.

Broken
stateDiagram-v2
    state Both {
        [*] --> A
        ---
        [*] --> B
    }
Fixed
stateDiagram-v2
    state Both {
        [*] --> A
        --
        [*] --> B
    }

What you see

Parse error on line 1, ending in: got 'ID'

Why

A version suffix that does not exist. There is `stateDiagram` and `stateDiagram-v2`, and nothing else — `-v3` fails at the first line.

Fix

Use `stateDiagram-v2`.

Broken
stateDiagram-v3
    [*] --> Draft
Fixed
stateDiagram-v2
    [*] --> Draft

What you see

It renders, but one state has silently become several boxes

Why

A space in a state id. Mermaid does not reject it, and it does not read the rest as a description — it creates a separate box for every word. Measured by reading the emitted state ids: `[*] --> Awaiting review` produces two states, `Awaiting` and `review`, and only the first is on the end of the arrow; the other just sits there unconnected. A three-word name gives three boxes, so the diagram quietly grows sideways. The description mechanism is real, but it needs a colon — `review: waiting for a reviewer` — which is what this mistake gets confused with.

Fix

Declare the state with `state "Label" as id` and always refer to it by the id.

Broken
stateDiagram-v2
    [*] --> Awaiting review
    Awaiting review --> Done
Fixed
stateDiagram-v2
    state "Awaiting review" as review
    [*] --> review
    review --> Done

What you see

It renders, but the choice node is drawn as an ordinary state

Why

The `<<choice>>` declaration came after the transitions that use it. Mermaid creates the state the first time it is mentioned, and a later stereotype does not change what has already been created.

Fix

Declare pseudo-states before the transitions that reference them.

Broken
stateDiagram-v2
    [*] --> check
    check --> Approved
    check --> Rejected
    state check <<choice>>
Fixed
stateDiagram-v2
    state check <<choice>>
    [*] --> check
    check --> Approved
    check --> Rejected

Rendering notes

Measured against Mermaid 11.12.2 as this site runs it.

Both stateDiagram and stateDiagram-v2 render — which is a trap

A common piece of advice is that you must use `stateDiagram-v2` or nothing will draw. That is not true in 11.12.2: both keywords render without error. The difference is layout quality, particularly for composite and concurrent states, and there is no warning when you use the old one. If a composite state looks cramped or the arrows route oddly, check which keyword you opened with before you start rewriting the diagram.

Height grows about 108px per state

Three states render to a viewBox of roughly 52×462; forty states to 60×4680. As with flowcharts, the width barely moves — state machines grow downward. `direction LR` inside the diagram is the usual fix when a lifecycle is long but shallow.

Composite states are laid out independently

The inner machine of a composite state is sized on its own and then placed, which is why a single large composite can push the whole diagram much wider than the state count suggests. If one box dominates, promoting its contents to the top level and linking to a second diagram usually reads better than fighting the layout.

Labels are HTML, so PNG export re-renders

Like flowchart, class and ER diagrams, state labels are drawn inside an SVG `<foreignObject>`. Browsers refuse to rasterise that onto a canvas, so PNG export on this site re-renders the diagram with plain SVG text labels first. The PNG is correct and full-size; the label typography is very slightly different from the screen.

Theme changes colour, never layout

Default and dark themes produce an identical viewBox for the same source, so a state machine cannot reflow when the theme changes.

When to use something else

If your labels are verbs — validate, send, retry — you are describing a process, not a lifecycle, and a flowchart is the honest choice. The clearest signal is that you cannot answer the question "what is the thing that is in this state?"

If several components each have their own lifecycle and the interesting part is how they interact, one state diagram per component plus a sequence diagram for the interaction beats one enormous machine.

And if every state connects to every other state, the diagram will be a hairball no matter how it is drawn. That usually means the states are not really states but flags that combine freely — in which case a table of valid combinations communicates far more than a picture.

Other diagram types

Written by Dominik Malsch · Last updated:

Open the editor →