Mermaid flowchart editor
A flowchart shows how control moves through a process: steps, branches, and where the branches rejoin. Reach for one when the interesting part is the order of decisions — a deployment pipeline, a request path, an approval route. If the interesting part is who talks to whom over time, you want a sequence diagram instead.
A CI pipeline with two failure paths
This is the shape most flowcharts on this site start as: a linear happy path with decision nodes that break out of it. Note the quoted label on the last node — brackets inside a label need quoting, which is the single most common flowchart error.
flowchart TD
Push[Push to main] --> Lint[Lint and typecheck]
Lint --> Test{Tests pass?}
Test -->|no| Fail[Notify author on Slack]
Test -->|yes| Build[Build container image]
Build --> Scan{CVE scan clean?}
Scan -->|no| Block["Block release (needs triage)"]
Scan -->|yes| Deploy[Deploy to production]
Deploy --> Smoke[Run smoke tests]
Smoke --> Done[Release complete]Worked examples
1. The minimum useful flowchart
Two nodes and an arrow. `TD` means top-down; `LR` gives you left-to-right, which is usually better for anything wider than it is tall.
flowchart TD
Request[Incoming request] --> Response[Response sent]2. A decision with labelled branches
Curly braces make a diamond. The text between pipes labels the edge, not the node — that distinction matters when you hit the errors section below.
flowchart TD
Start[Request received] --> Auth{Valid token?}
Auth -->|yes| Handler[Run handler]
Auth -->|no| Reject[Return 401]
Handler --> Done[Return 200]3. Node shapes that carry meaning
Shape is the cheapest way to add information to a flowchart. Rounded for start and end, diamond for a decision, cylinder for storage, and the doubled shape for a terminal state.
flowchart LR
Start([Job scheduled]) --> Read[(Read from Postgres)]
Read --> Check{Rows to process?}
Check -->|none| Stop([Exit 0])
Check -->|some| Work[/Transform rows/]
Work --> Write[(Write to S3)]
Write --> Stop4. Subgraphs for grouping by owner
Subgraphs draw a box around related nodes. The most useful thing to group by is not process stage but ownership — which team or service is responsible for which part, so the handoffs become visible.
flowchart TD
subgraph client [Browser]
UI[User submits form]
end
subgraph api [Order service]
Validate[Validate payload]
Persist[Write order row]
end
subgraph async [Background workers]
Email[Send confirmation]
Invoice[Generate invoice]
end
UI --> Validate
Validate --> Persist
Persist --> Email
Persist --> Invoice5. A retry loop with a bounded exit
Flowcharts handle cycles fine, and a retry loop is where they earn their keep — the diagram makes it obvious whether the loop has an exit. Note `Retry` counts as an ordinary node; only lowercase `end` is reserved.
flowchart TD
Send[Send webhook] --> Result{2xx response?}
Result -->|yes| Ack[Mark delivered]
Result -->|no| Count{Attempt < 5?}
Count -->|yes| Wait[Back off exponentially]
Wait --> Send
Count -->|no| Dead[Move to dead letter queue]Flowchart syntax reference
Everything below is flowchart-only syntax. Arrow forms in particular do not carry over to other diagram types — a sequence diagram's `->>` is a parse error here.
| Syntax | Meaning |
|---|---|
| flowchart TD | Top-down. Also TB. The default reading order for a process. |
| flowchart LR | Left-to-right. Also RL. Better for wide, shallow flows. |
| A[Text] | Rectangle — an ordinary step. |
| A(Text) | Rounded rectangle. |
| A([Text]) | Stadium shape — conventionally a start or end point. |
| A[(Text)] | Cylinder — a datastore. |
| A{Text} | Diamond — a decision. |
| A[/Text/] | Parallelogram — input or output. |
| A --> B | Arrow. |
| A --- B | Line with no arrowhead. |
| A -.-> B | Dotted arrow — conventionally async or optional. |
| A ==> B | Thick arrow — conventionally the primary path. |
| A -->|label| B | Labelled edge. Quote the label if it contains brackets. |
| A["Text (with brackets)"] | Quoted label — required for brackets, quotes, or anything the parser would read as shape syntax. |
| subgraph name [Title] ... end | Group nodes in a labelled box. `end` closes it. |
| %% comment | Comment line, not rendered. |
Six errors that actually break flowcharts
Each of these was reproduced against the renderer this site runs (Mermaid 11.12.2). Paste the broken version into the editor and you will get exactly the error described; the fixed version renders. The fastest way to read a Mermaid parse error is to look at the very end of the message, where it names the token it choked on.
What you see
Parse error, ending in: got 'PS'
Why
An opening parenthesis inside a square-bracket label. Parentheses are shape syntax — `A(text)` is a rounded node — so a bare `(` inside `[...]` is read as the start of a shape.
Fix
Wrap the whole label in double quotes. Anything inside quotes is treated as literal text.
flowchart TD
A[Retry (max 5)] --> B[Done]flowchart TD
A["Retry (max 5)"] --> B[Done]What you see
Parse error, ending in: got 'STR'
Why
A double quote inside a label. The parser treats it as the start of a quoted string and then hits the closing bracket where it expected the matching quote.
Fix
Use single quotes inside a double-quoted label, or write the character as the entity `#quot;`.
flowchart TD
A[Status is "pending"] --> B[Done]flowchart TD
A["Status is 'pending'"] --> B[Done]What you see
Parse error, ending in: got 'end'
Why
`end` used as a node id. Lowercase `end` closes a subgraph, so the parser sees a block terminator where a node should be. This one is common precisely because `end` is the natural name for a final node.
Fix
Capitalise it, or give the node an id and put the word in the label.
flowchart TD
Start[Begin] --> endflowchart TD
Start[Begin] --> End[Finished]What you see
Parse error on the line where you named a node
Why
A space in the node id. The id is the token before the arrow, and a space terminates it, leaving a second bare word the parser cannot place.
Fix
Use a single-word id and put the readable text in the label.
flowchart TD
auth service --> user databaseflowchart TD
auth[Auth service] --> db[(User database)]What you see
Parse error on an edge label between pipes
Why
Brackets inside an edge label. `|...|` has the same restriction as a node label — parentheses there are still shape syntax.
Fix
Quote the edge label as well.
flowchart TD
A -->|retry (once)| Bflowchart TD
A -->|"retry (once)"| BWhat you see
Lexical error on line 1. Unrecognized text.
Why
An invalid direction. Flowcharts accept TB, TD, BT, LR and RL and nothing else, and an unknown one fails in the lexer before any node is read — which is why the error points at line 1 rather than at your mistake.
Fix
Use one of the five. TD and LR cover nearly everything.
flowchart TOPDOWN
A --> Bflowchart TD
A --> BRendering notes
Measured against Mermaid 11.12.2 as this site runs it, rather than taken from the documentation. These are the behaviours that matter once a flowchart stops being a toy.
Height grows about 105px per node; width barely moves
A top-down flowchart of 3 nodes renders to a viewBox of roughly 122×382. At 40 nodes it is 131×4230 — the width grew by nine pixels and the height by a factor of eleven. Long flowcharts become tall ribbons that no longer fit any screen, which is what the centre button in the preview is for. If a diagram is getting away from you vertically, switching to `flowchart LR` costs one word and often halves the aspect ratio.
Labels are HTML, and that used to break PNG export
Flowchart labels are drawn inside an SVG `<foreignObject>` containing real HTML. That is why `<br>` and basic markdown work inside a label. It also means the browser refuses to rasterise the SVG onto a canvas, which for a long time made PNG export on this site silently hand back an SVG file instead. Export now re-renders the diagram with plain SVG text labels, so PNG works — at the cost of very slightly different label typography in the PNG compared to the screen.
Theme changes colour, never layout
Rendering the same flowchart with the default and dark themes produces a byte-identical viewBox. Switching theme cannot reflow a diagram or push a label out of its box, so if something looks wrong in dark mode it will look equally wrong in light mode.
The exported image is sized from the viewBox, not the screen
Mermaid emits `width="100%"` and no height attribute, so the on-screen size depends on the container. Export reads the viewBox instead and renders at two to three times that, which is why a PNG of a tall flowchart comes out far larger than what you were looking at. Zoom level does not affect the export.
Only lowercase `end` is reserved
`End`, `END` and `ending` are all ordinary node ids. This is worth knowing because the obvious workaround — renaming the node — is usually unnecessary; changing one letter's case is enough.
When to use something else
If the diagram is mostly about who sends what to whom, and the order in time matters more than the branching, a sequence diagram will be clearer and will stay clearer as it grows. A flowchart with six participants encoded as node names is a sequence diagram that has not admitted it yet.
If you are describing the states an object can be in rather than the steps a process goes through, use a state diagram. The test is simple: if your node labels are nouns with adjectives ("order pending", "order shipped") it is a state machine; if they are verbs ("validate payload", "send email") it is a flowchart.
And if the flowchart is over about forty nodes, the honest answer is that no diagram type will save it. Split it into several diagrams with one shared entry point, or accept that the thing you are describing is too complicated to be understood in one picture — which is itself useful information.
Other diagram types
Written by Dominik Malsch · Last updated: