State diagrams answer a different question than flowcharts and sequence diagrams.
- Flowcharts: What steps happen?
- Sequence diagrams: What calls happened in what order?
- State diagrams: What states can this thing be in, and what events move it between states?
If you’ve ever tried to explain “healthy → draining → terminated” (or “closed → open → half-open”), a state diagram is usually the cleanest way to do it.
This post focuses on Mermaid state diagrams for modeling lifecycles you’ll actually run into in ops and engineering: deploys, load balancers, workers, and circuit breakers.
A quick refresher: the minimum you need
Mermaid’s modern syntax is stateDiagram-v2.
Source
|
1 2 3 4 5 6 7 8 |
stateDiagram-v2 [*] --> Idle Idle --> Running: start Running --> Idle: stop Running --> Failed: crash Failed --> Idle: recover Idle --> [*] |
Rendered
Conventions worth adopting
- Use nouns for states:
Healthy,Draining,Degraded - Use verbs/events on arrows:
timeout,deploy,deregister,success - Keep labels short; if you need paragraphs, add a note or link to a runbook
1) Model “system lifecycle” states (a great first use)
Many lifecycles share the same shape: Created → Starting → Active → Stopping → Stopped, with a failure path.
Source
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
stateDiagram-v2 [*] --> Created Created --> Starting: provision Starting --> Active: ready Starting --> Failed: error Active --> Stopping: shutdown Stopping --> Stopped: exited Failed --> Stopping: cleanup Stopping --> Stopped Stopped --> [*] |
Rendered
2) Composite states (when one state has an internal lifecycle)
This is the “beyond basics” feature that makes state diagrams scale.
Here, Active contains its own mini-state machine.
Source
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
stateDiagram-v2 [*] --> Active state Active { [*] --> Healthy Healthy --> Degraded: latency_high Degraded --> Healthy: recovery Degraded --> Unhealthy: error_rate_high Unhealthy --> Degraded: partial_recovery } Active --> [*]: terminate |
Rendered
When your diagram starts looking crowded, composite states are usually the right move.
3) A practical ops example: ALB target lifecycle (healthy → draining → unused)
If you’ve worked with load balancers, you’ve seen variants of this story.
Even if exact labels differ across systems, the lifecycle is recognizable:
- A target can be Registered
- It becomes Healthy after checks
- During scale-in/deploy it becomes Draining
- Then becomes Unused and can be terminated
Source
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
stateDiagram-v2 [*] --> Registered Registered --> Initial: register Initial --> Healthy: health_checks_pass Initial --> Unhealthy: health_checks_fail Healthy --> Draining: deregister_or_scale_in Draining --> Unused: delay_elapsed Unhealthy --> Draining: remove_from_service Draining --> Unused Unused --> [*]: terminate_instance |
Rendered
4) Another great fit: circuit breaker lifecycle (closed/open/half-open)
This is a classic state machine—and a perfect candidate for a state diagram.
Source
|
1 2 3 4 5 6 7 8 9 |
stateDiagram-v2 [*] --> Closed Closed --> Open: failures_exceed_threshold Open --> HalfOpen: sleep_window_elapsed HalfOpen --> Closed: probe_success HalfOpen --> Open: probe_failure |
Rendered
If you add one detail, make it what counts as a failure and the sleep window—those are usually the knobs people debate.
5) Background worker lifecycle (with a “paused” state)
Worker lifecycles are often misunderstood during incidents. State diagrams make it clear what’s allowed.
Source
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
stateDiagram-v2 [*] --> Stopped Stopped --> Starting: start Starting --> Running: ready Running --> Busy: job_received Busy --> Running: job_complete Busy --> Failed: exception Running --> Paused: operator_pause Paused --> Running: resume Failed --> Paused: quarantine Paused --> Stopped: shutdown Running --> Stopped: shutdown |
Rendered
6) When to choose a state diagram vs a flowchart
Choose a state diagram when:
- You’re describing a thing that can be in a limited set of conditions
- You care about what transitions are allowed (and what aren’t)
- The same event can have different outcomes depending on the current state
Choose a flowchart when:
- You’re describing a process with steps
- You want to show branching logic and sequencing
A handy rule:
- States are nouns. Transitions are verbs.
7) A “blog-ready” checklist for lifecycle diagrams
Before you publish:
- Start with the happy path, then add failure paths.
- Avoid too many states. If you need more than ~10, consider a composite state.
- Use consistent event naming:
timeout,deploy,rollback,scale_in. - Ensure every state has a plausible exit (or note why it doesn’t).
- If a transition requires a timer, label it explicitly (
delay_elapsed,sleep_window_elapsed).
Where to go next
If you’re modeling incidents, state diagrams pair beautifully with sequence diagrams:
- Use the sequence diagram to show what happened.
- Use the state diagram to show why the system behaved that way given its current state.




