Learn (Almost) Anything
CatalogDownload course

Diagrams as Code with Mermaid

stateDiagram-v2 for lifecycles and status machines: states, transitions, the [*] start/end markers, composite states, and forks. Then Gantt charts for project plans: the date format and axis, sections, task dependencies (after), milestones, and marking done/active/crit tasks. Two different shapes of thinking — flow over states vs. work over time.

enMini-course6 lessons1 module5
Diagrams as Code with MermaidMermaid Diagrams in Practicemermaiddiagramscodepractice

State Diagrams and Gantt Charts

stateDiagram-v2 for lifecycles and status machines: states, transitions, the [*] start/end markers, composite states, and forks. Then Gantt charts for project plans: the date format and axis, sections, task dependencies (after), milestones, and marking done/active/crit tasks. Two different shapes of thinking — flow over states vs. work over time.

State Diagrams and Gantt Charts

These two diagram types answer the same class of question: what happens over time? State diagrams track an entity moving through statuses — a request, an order, a user session. Gantt charts track work moving through a schedule. Same underlying question, completely different shapes of syntax.

stateDiagram-v2: the fundamentals

Always use stateDiagram-v2 — the older stateDiagram keyword still parses but uses a different renderer with limited layout control.

The most important symbol is [*], which marks entry and exit:

stateDiagram-v2
    [*] --> Draft
    Draft --> PendingReview : submit
    PendingReview --> Published : approve
    PendingReview --> Draft : reject
    Published --> Archived : archive
    Archived --> [*]

A colon after a transition adds a label. [*] as the source means the lifecycle starts here; as the target, this is terminal. A diagram without a [*] entry technically renders, but the reader has no idea where the lifecycle begins — always include it.

State IDs can't contain spaces. If you need a multi-word display name, alias it:

state "Pending Review" as PendingReview

After that declaration, PendingReview is what you write in transition lines; "Pending Review" is what renders in the box.

Want a horizontal layout? Add direction LR on the line right after stateDiagram-v2 — this is a v2-only feature and one more reason to always use the modern keyword.

stateDiagram-v2 [*] --> Draft Draft --> PendingReview : submit PendingReview --> Published : approve PendingReview --> Draft : reject Published --> Archived : archive Archived --> [*]
stateDiagram-v2
    [*] --> Draft
    Draft --> PendingReview : submit
    PendingReview --> Published : approve
    PendingReview --> Draft : reject
    Published --> Archived : archive
    Archived --> [*]
A document lifecycle: [*] marks where the lifecycle begins and where it ends

Composite states

When a state has its own internal lifecycle, nest it with curly braces:

stateDiagram-v2
    [*] --> Active

    state Active {
        [*] --> Idle
        Idle --> Processing : request in
        Processing --> Idle : response sent
        Processing --> Failed : timeout
        Failed --> Idle : retry
    }

    Active --> Terminated : shutdown
    Terminated --> [*]

The outer world sees Active as a single state — you enter and exit it as a unit. Internally it has its own [*] entry that fires when Active is entered. The outer Active --> Terminated transition fires regardless of which inner sub-state was active at the time. Nesting deeper than two levels usually signals the diagram should be split — same rule as with subgraphs in flowcharts.

stateDiagram-v2 [*] --> Active state Active { [*] --> Idle Idle --> Processing : request in Processing --> Idle : response sent Processing --> Failed : timeout Failed --> Idle : retry } Active --> Terminated : shutdown Terminated --> [*]
stateDiagram-v2
    [*] --> Active

    state Active {
        [*] --> Idle
        Idle --> Processing : request in
        Processing --> Idle : response sent
        Processing --> Failed : timeout
        Failed --> Idle : retry
    }

    Active --> Terminated : shutdown
    Terminated --> [*]
A composite state: Active has its own internal lifecycle; from outside it still looks like a single state

Concurrency: parallel regions and fork/join

Two ways to model activity that happens simultaneously:

Concurrent regions inside a composite state, separated by --:

stateDiagram-v2
    state "Order Processing" as Proc {
        [*] --> PaymentPending
        PaymentPending --> PaymentConfirmed : paid
        PaymentConfirmed --> [*]
        --
        [*] --> InventoryCheck
        InventoryCheck --> Reserved : ok
        Reserved --> [*]
    }

The -- line splits the composite state box into horizontal swim lanes that run independently.

A composite state box divided into two independent horizontal swim lanes by the -- separator.

Fork/join for branches that diverge and later reconverge:

stateDiagram-v2
    [*] --> fork_state
    state fork_state <<fork>>
    fork_state --> RunTests
    fork_state --> BuildDocs

    RunTests --> join_state
    BuildDocs --> join_state
    state join_state <<join>>
    join_state --> Deploy
    Deploy --> [*]

<<fork>> and <<join>> are state stereotypes — the rendered result is a solid horizontal bar, the standard UML convention. Use <<fork>> when multiple things must happen simultaneously; <<join>> when all must complete before the flow continues.

UML fork and join bars as rendered in a Mermaid state diagram: a solid bar fans out to parallel branches, then another solid bar merges them back.

---

Gantt charts: the date/axis setup

Switch keyword to gantt. The lines to write every time:

gantt
    dateFormat  YYYY-MM-DD
    axisFormat  %b %d
    title       Website Launch Plan

dateFormat tells the parser how to read the dates you write in task lines. Skip it and any task with an absolute start date won't parse — you get a blank diagram with no error message whatsoever. YYYY-MM-DD is the safest choice and almost universal.

axisFormat controls how dates appear on the rendered timeline, using strftime notation: %b %d gives "Jan 06", %m/%d gives "01/06", %d gives just the day number. This affects display only, not parsing.

Task syntax and flags

Tasks live under section headers. The format:

Task label  :flags, id, start, duration

A realistic project plan:

gantt
    dateFormat  YYYY-MM-DD
    axisFormat  %b %d
    title       API v2 Launch

    section Design
    Define endpoints      :done,  des1, 2024-03-01, 5d
    Review with team      :done,  des2, after des1, 2d

    section Development
    Implement auth        :active, dev1, after des2, 7d
    Write integration tests : dev2, after dev1, 4d

    section Launch
    Deploy to staging     :crit, dep1, after dev2, 1d
    Go live               :milestone, live, after dep1, 0d

Flag reference:

FlagEffect
doneFilled/gray bar — task complete
activeHighlighted (typically blue) — in progress
critRed bar — on the critical path
milestoneDiamond marker — duration must be 0d

Flags combine freely: :crit, done marks a finished critical-path task. The parser recognizes those four keywords as flags; anything else in that position is treated as a task ID. So :dev2, after dev1, 4d assigns the id dev2 with no status flag.

Dependencies and milestones

after taskId as the start value makes a task begin the moment the referenced task ends. Chain multiple predecessors — after dev1 dev2 — and the task waits for both to finish before starting. This is the Gantt counterpart to <<join>> in state diagrams.

Milestones mark a point in time rather than a span of work. The 0d duration is what triggers the diamond rendering:

Go live  :milestone, live, after dep1, 0d

excludes weekends at the top level removes those days from duration calculations — a 5-day task starting Thursday automatically extends into the following week.

gantt dateFormat YYYY-MM-DD axisFormat %b %d title API v2 Launch section Design Define endpoints :done, des1, 2024-03-01, 5d Review with team :done, des2, after des1, 2d section Development Implement auth :active, dev1, after des2, 7d Write integration tests : dev2, after dev1, 4d section Launch Deploy to staging :crit, dep1, after dev2, 1d Go live :milestone, live, after dep1, 0d
gantt
    dateFormat  YYYY-MM-DD
    axisFormat  %b %d
    title       API v2 Launch

    section Design
    Define endpoints      :done,  des1, 2024-03-01, 5d
    Review with team      :done,  des2, after des1, 2d

    section Development
    Implement auth        :active, dev1, after des2, 7d
    Write integration tests : dev2, after dev1, 4d

    section Launch
    Deploy to staging     :crit, dep1, after dev2, 1d
    Go live               :milestone, live, after dep1, 0d
A Gantt plan with done, active, crit, and milestone tasks — all chained with after dependencies

Quick check

InteractiveState & Gantt Syntax Quiz
Four quick questions on stateDiagram-v2 and Gantt syntax. Click an answer to get instant feedback and a brief explanation.

1. Draw a stateDiagram-v2 for a support ticket: Open → InProgress → PendingCustomer → Resolved → Closed → [*], with an edge from Closed back to Open labeled "re-open."

2. Add a composite state inside InProgress with two sub-states: Assigned and WorkingOnFix.

3. Write a five-task Gantt for a small feature rollout — at least one done task, one active, one crit, and a milestone at the end. Use after dependencies throughout.

The next submodule covers layout control, styling with classDef, theme variables, and clickable nodes — where your own-site rendering setup really starts to pay off.

Self-check

  1. You see a state diagram without any [*] markers. The diagram renders without errors. Why would you still add [*] to make it more correct?
  2. You need to display a state as 'Pending Review' in the diagram. Why write `state "Pending Review" as PendingReview` instead of just `state PendingReview`?
  3. Inside a composite state Auth with sub-states Login and TwoFactor, you define `Auth --> Logout`. What is the consequence of this transition firing?
  4. You're modeling a checkout process where payment validation and inventory checking must happen simultaneously. Which structure fits best?
  5. In a Gantt chart, you omit the `dateFormat` line and use task dates like '2024-03-01'. What is the result?
  6. What is the core difference between `dateFormat YYYY-MM-DD` and `axisFormat %b %d` in a Gantt diagram?
  7. You create a task `ship_date :milestone, m1, after deploy, 1d`. Why is this problematic?
  8. In a Gantt chart, you write `Integration :crit, int, after dev1 dev2, 3d`. When does Integration start?

Homework

Content Publishing Workflow State Diagramdocument

Create a state diagram that models how articles move through a publishing pipeline. Track these states: Draft (initial), Review, Revision, Approved, Published, and Archived (terminal). Include a transition from Review back to Revision when an article needs changes, and from Revision back to Review once the author resubmits. Label each transition with what triggers it (e.g., 'submit for review', 'reject', 'approve', 'publish', 'archive'). You can use multi-word state names—alias them if needed. Submit your work as a markdown file with the Mermaid code block.

Diagram uses stateDiagram-v2; [*] marks both entry and exit; all six required states are present with unique IDs; transitions connect states logically and each has a label; the feedback loop from Review to Revision is correctly implemented; diagram renders without syntax errors; code is properly indented and readable.

Sprint Development Gantt Chartdocument

Create a Gantt chart for a typical two-week development sprint. Include these phases: Sprint Planning, Development, Quality Assurance, and Release. Add 6–8 tasks spanning these phases (e.g., 'Review requirements', 'Implement feature X', 'Write unit tests', 'Run integration tests', 'Deploy to staging', 'Go live'). Use task dependencies so that testing doesn't start until development is complete, and the release happens only after QA signs off. Mark at least one task as critical (on the critical path), mark one or two as done (completed before this sprint), and create a 'Go live' milestone at the end. Use dateFormat YYYY-MM-DD and choose an axisFormat that's readable (e.g., %b %d). Submit as a markdown file with the Mermaid code block.

Diagram declares dateFormat YYYY-MM-DD and axisFormat; all tasks belong to clearly named sections; at least 6–8 tasks are defined with realistic start dates and durations; task IDs are unique; dependencies use 'after' correctly so testing waits for dev and release waits for QA; at least one :crit task, at least one :done task; a milestone is present with 0d duration and renders as a diamond; dates are sequential and realistic for a two-week sprint; diagram renders without parse errors.

Feature Request Lifecycle: State Diagram + Ganttdocument

Build a document that shows how a feature request moves through your organization's workflow. Include two parts: First, create a state diagram modeling the feature request lifecycle with states for Submitted, Under Review, Approved, In Development, Testing, Shipped, and Archived. Add transitions and feedback loops—for example, a path back to Under Review if a feature is rejected, and a path back to In Development if testing finds critical bugs. Second, create a Gantt chart showing the timeline for one specific feature request flowing through these stages. Include at least one task per major phase, dependencies that reflect the state flow, at least one milestone for 'Shipped', and a mix of task flags (done, active, crit). Finally, write 2–3 sentences explaining what the state diagram tells you that the Gantt chart doesn't—and vice versa. Submit as a single markdown file with both diagram code blocks, clear section headers, and your explanation.

State diagram uses stateDiagram-v2 with [*] entry and [*] exit; all required states present with no spaces in IDs (or properly aliased); transitions have labels; feedback loops for rejection and bugs are correctly implemented; Gantt has dateFormat and axisFormat declared; Gantt includes at least 6–7 tasks organized in sections aligned with the state diagram; tasks have dependencies (after) reflecting the state flow; Gantt includes a milestone with 0d duration, at least one :crit task, and at least one :done task; explanation clearly articulates what each diagram shows differently (e.g., state diagram shows branching logic and decision points, Gantt shows timing and sequence); both diagrams render cleanly without errors; markdown is well-organized with clear headers for each section.

Submit and get assignments reviewed in the Learn (Almost) Anything app.

Sources

  1. State diagrams | Mermaid
  2. Mermaid stateDiagram syntax source | GitHub
  3. Gantt diagrams | Mermaid