learn-mermaid-with-phoebe / Session 2 of 6
Learn Mermaid with Phoebe · Session 2 of 6

Tame the spaghetti: flowchart mastery

Session 1 gave you nodes and arrows. Today you get the three tools that turn a tangle into a diagram people thank you for: subgraphs for structure, classes for meaning, and the hygiene habits that keep big diagrams readable.

🟢 Easy Data & AI teams 45 min live + self-study
0-3 · Recap 3-22 · Concepts (live cards) 22-40 · Three demos 40-45 · Q&A
Part 0

Why this session exists

Every flowchart starts clean. Then someone adds "just one more box" ten times, and now it reads like a plate of noodles. That homework diagram you brought - the one that grew past 10 nodes - is today's patient. The cure is not a bigger monitor: it is grouping (subgraphs), visual meaning (classes), and knowing when one diagram should become two. Nova's map gets the full treatment too.

Live - presented in session Self-study - read after class ★ Try it now Every pink diagram block is REAL mermaid, rendered live
★ What you walk out with today Subgraph syntax for zoning a diagram, classDef styling that gives every color one job, the v11 shape catalog, click-to-link interactivity, and a rescued Nova map: three named zones, styled by workload, each node linking to its (fictional) repo. Plus a repeatable recipe for rescuing any messy flowchart you inherit.
Part 1 · covers "Flowchart: subgraphs"

Subgraphs - boxes within boxes 7 min live

A subgraph draws a labeled container around a group of nodes. Readers scan the containers first and the boxes second - which means a 20-node diagram with 3 zones reads like a 3-node diagram. That is the whole trick.

Sources Events CRM Platform Pipeline Warehouse Consumers Dashboards ML Readers scan the three zones first, the boxes second. Structure does the explaining.
🔍 Click to zoom - the zoning mental model: containers carry the story, nodes carry the detail.
LiveThe subgraph block3 min▶

A subgraph is three things: the keyword, an ID with an optional display title, and an end. Everything declared between them lives inside the box. Edges work exactly as before - including edges that cross the box wall, and edges attached to the subgraph ID itself.

flowchart LR
  subgraph src[Sources]
    ev[App events]
    crm[CRM export]
  end
  subgraph plat[Platform]
    ing[Ingestion] --> qa{Quality checks}
    qa -->|pass| dw[(Warehouse)]
  end
  subgraph cons[Consumers]
    bi[Dashboards]
    ml[ML features]
  end
  ev -->|stream| ing
  crm -.->|nightly| ing
  dw --> bi
  dw --> ml
  • Always give the ID: subgraph src[Sources]. The ID (src) is how you draw edges to the whole zone later - src --> plat connects box wall to box wall.
  • Declare inside, connect anywhere. A node's home is the subgraph where it is first declared. Cross-zone edges (like ev --> ing) are fine and normal.
  • Nesting works: a subgraph inside a subgraph draws boxes within boxes - handy for a "Platform" zone containing "Streaming" and "Batch" sub-zones.
Real world

The architecture review that finally landed. A platform team presented the same 25-node diagram twice. Flat version: execs squinted, meeting drifted. Zoned version - Sources, Our platform, Downstream teams - the CFO pointed at the middle box and asked exactly the right cost question. Same nodes, three subgraphs, different meeting.

LiveDirection inside a subgraph2 min▶

Each subgraph can set its own flow with a direction statement on its first line - a top-down zone inside a left-right diagram, for example:

Patternsubgraph plat[Platform] direction TB ing --> qa --> dw end
  • The catch (docs say so too): if any node inside the subgraph links to a node outside it, the subgraph's own direction is ignored and it inherits the parent flow. Design zones as units first, wire them second.
  • When it shines: a wide LR pipeline with one tall TB zone for a decision ladder or an approval chain.
Self-studyZone design - what makes a good subgraph2 min read▶

Subgraphs are a grouping tool, and groupings are claims: "these things belong together". Good claims to make:

  • Ownership - one zone per team or system boundary. The best default for architecture diagrams.
  • Lifecycle stage - raw / staged / served zones in a data platform.
  • Trust boundary - inside the VPC vs outside; great for security conversations.

Bad claim: grouping by "stuff that happened to fit there". If you cannot name the zone in two words, it is not a zone. And 3-5 zones is the sweet spot - seven subgraphs is spaghetti with extra steps.

Part 2 · covers "Flowchart: styling and classes"

Styling - meaning through color 7 min live

Untrained color is decoration. Trained color is a legend: stream things pink, batch things pale, storage things dark - and suddenly readers decode your diagram before reading a single label. Mermaid's tool for this is classDef.

LiveclassDef + class - define once, apply everywhere3 min▶

A classDef names a reusable style. A class statement (or the ::: shorthand right on a node) applies it. One definition, any number of nodes - exactly like CSS.

flowchart LR
  ev[App events]:::stream -->|stream| ing[Ingestion]
  crm[CRM export]:::batch -.->|nightly| ing
  ing --> dw[(Warehouse)]
  dw --> bi[Dashboards]
  class dw storage
  linkStyle 1 stroke:#F59E0B,stroke-width:3px
  classDef stream fill:#D6246E,color:#FFEFF5,stroke:#8E1146
  classDef batch fill:#FFEFF5,color:#8E1146,stroke:#D6246E
  classDef storage fill:#8E1146,color:#FFEFF5,stroke:#8E1146
StatementDoesUse when
classDef name fill:...,stroke:...defines a named stylealways - your palette lives here
class a,b,c nameapplies it to listed nodesstyling many nodes at once
a[Label]:::nameapplies it inlinestyling at the point of declaration
style a fill:#FFEFF5styles ONE node directlya true one-off (rare - prefer classes)
linkStyle 1 stroke:#F59E0Bstyles edge number 1 (0-based, in source order)highlighting one critical edge
House style Define every classDef at the BOTTOM of the block, together. Content first, palette last - the next editor finds all styling in one place, and your diff stays readable when the palette changes.
LiveOne meaning per color - the discipline2 min▶

Class names should name MEANINGS (stream, batch, storage, deprecated), never looks (pinkBox, dark2). If a color means two things in one diagram, it means nothing.

Color chaosclassDef red fill:#D6246E class ev,dw,alerts red %% streaming? storage? on fire? nobody knows
Color legendclassDef stream fill:#D6246E,color:#FFEFF5 classDef storage fill:#8E1146,color:#FFEFF5 class ev stream class dw storage %% every color has exactly one job
Real world

The migration diagram that ran itself. A data team marked every legacy node with a deprecated class (pale fill, dashed stroke). Each migration PR moved one node out of the class. The diagram became the burndown chart - stakeholders watched the pale boxes disappear week by week, no status deck required.

Self-studyv11 expanded shapes - a bigger vocabulary3 min read▶

Mermaid v11.3+ added a second way to pick shapes: the @{ } attribute syntax. Instead of memorizing bracket gymnastics, you name the shape - and the catalog grew to 30+ shapes (see flowchart.html#expanded-node-shapes in the docs).

flowchart LR
  raw@{ shape: cyl, label: "Raw zone" } --> job@{ shape: rect, label: "Transform job" }
  job --> marts@{ shape: cyl, label: "Marts" }
  job --> rules@{ shape: hex, label: "Quality rules" }
  • Handy names: cyl (database), diam (decision), stadium (start/end), hex (preparation), circle, rounded, rect.
  • When to use which style: brackets for the daily six shapes (they type faster), @{ } when you need a shape brackets cannot make, or when generating mermaid programmatically.
  • Quote the label inside @{ } - it is already a habit from Session 1, and here it is required whenever the label has spaces.
Part 3 · covers "Flowchart: interaction" + big-diagram hygiene

Interaction + big-diagram hygiene 6 min live

Two finishing skills: making nodes clickable, and knowing when a diagram has outgrown one page. The second one matters more - no amount of styling saves a 60-node hairball.

One diagram, every question 20+ nodes, wires crossing, nobody reads it Overview map 3 zones, 9 nodes Ingestion detail one zone, zoomed in Serving detail one zone, zoomed in Each diagram answers ONE question; links carry readers between them.
🔍 Click to zoom - the split rule: one hairball becomes an overview plus zoomed details, connected by links.
LiveClick - nodes that go somewhere2 min▶

The click statement attaches a link (or a JavaScript callback) to a node. The pattern for links: click nodeId "https://..." "tooltip", with an optional _blank target at the end to open a new tab.

  • Links: click dw "https://example.com/warehouse" "Open the docs" - the node becomes a hyperlink.
  • Callbacks: click dw call myFunction() runs page JavaScript - for self-hosted pages and internal tools.
  • The GitHub caveat: GitHub strips click interactions when rendering fences, for security. Clicks work in mermaid.live, self-hosted pages (like this one), and most docs sites - treat them as a bonus layer, never as the only way to reach the information.
LiveWhen to split, how to link2 min▶

The split signal is not a node count - it is a question count. A good diagram answers one question ("how does data flow through Nova?"). When yours starts answering three, split it:

  • Overview diagram: zones only, maybe 8-12 nodes, the map of maps.
  • Detail diagrams: one per zone, as deep as needed. Each lives next to the code it describes.
  • Link them: click links where supported, plain markdown links under the fence everywhere else. The overview links down; each detail links back up.

Practical threshold: past roughly 20 nodes, start looking for the seam. Past 30, you are overdue.

Self-studyLayout nudging - the polite fixes2 min read▶

You cannot move boxes by hand, but you can nudge the layout engine, in escalating order:

  • Reorder declarations. Mermaid lays nodes out roughly in source order - moving the line that declares a node often untangles a crossing wire. Free, try it first.
  • Flip direction. LR to TD (or the reverse) re-deals the whole hand. Also free.
  • Invisible edges: a ~~~ b draws nothing but tells the engine "keep these ranked apart". The precision tool for two stubborn nodes that refuse to line up.
  • Longer arrows: extra dashes (---->) request extra rank distance, as in Session 1.
Budget rule Spend at most five minutes nudging. If the layout still fights you, the diagram is telling you it wants to be two diagrams.
Demo 1 of 3 · Nova levels up

Nova, zoned and styled ★ 8 min · follow along

We rebuild Session 1's map with everything from today: three subgraph zones, plus a three-class palette - stream, batch, storage - so the diagram explains its own workloads at a glance. Build it line by line in mermaid.live; the finished source is below.

flowchart LR
  subgraph src[Sources]
    ev[App events]:::stream
    crm[CRM export]:::batch
  end
  subgraph plat[Platform]
    ing[Ingestion] --> qa{Quality checks}
    qa -->|pass| dw[(Warehouse)]:::storage
    qa -->|fail| dlq[Quarantine]:::storage
  end
  subgraph cons[Consumers]
    bi[Dashboards]
    ml[ML features]
  end
  ev -->|stream| ing
  crm -.->|nightly| ing
  dw --> bi
  dw --> ml
  classDef stream fill:#D6246E,color:#FFEFF5,stroke:#8E1146
  classDef batch fill:#FFEFF5,color:#8E1146,stroke:#D6246E
  classDef storage fill:#8E1146,color:#FFEFF5,stroke:#8E1146

Start from your Session 1 source in mermaid.live. Wrap the two source nodes in subgraph src[Sources] ... end. Watch the container appear around them.

Zone the middle: move ingestion, quality checks, warehouse, and quarantine into subgraph plat[Platform]. Cross-zone edges keep working - only the declarations moved.

Zone the right: dashboards and ML features into subgraph cons[Consumers]. Three zones, story readable from the containers alone.

Add the palette at the bottom: three classDef lines - stream, batch, storage.

Apply with ::: at the point of declaration: ev[App events]:::stream, crm[CRM export]:::batch, and storage on both cylinders of truth - warehouse and quarantine.

Read it back as a stranger would: can you tell what streams, what batches, and where data rests, without reading a label? That is the pass condition.

Keep this source Nova v2 is the base for Session 4's data-model work and Session 6's theming. Save the mermaid.live share URL somewhere you will find it.
Demo 2 of 3

Rescue a messy diagram ★ 6 min · build your own

Here is a real-shaped mess: 15 nodes, zero structure, the diagram you inherit on day one of a new job. Your mission - group it into zones and restyle it using nothing but today's tools. No nodes may be harmed.

flowchart TD
  a[Web app] --> b[Event API]
  m[Mobile app] --> b
  b --> c[Kafka]
  c --> d[Stream job]
  e[CRM] --> f[Nightly export]
  f --> g[S3 landing]
  g --> h[Batch loader]
  d --> i[(Staging)]
  h --> i
  i --> j[dbt models]
  j --> k[(Marts)]
  k --> l[BI tool]
  k --> n[Feature store]
  n --> o[Model training]

Diagnose before cutting: read the node list and name the natural zones out loud. (One good answer: Producers, Streaming path, Batch path, Warehouse, Serving.)

Wrap each group in a titled subgraph. Declarations move inside the blocks; the edge lines stay where they are and keep working.

Flip TD to LR and compare. With zones in place, one direction will clearly read better - keep the winner.

Add a palette: stream and batch classes on the two paths, storage on the cylinders. Define the classDefs at the bottom, as always.

Count the wire crossings before and after. The rescue recipe - zones, direction, palette - typically cuts them to near zero without touching a single edge definition.

Real world

This rescue is a genuinely great first-week move on a new team. Take the scariest diagram in the wiki, zone and restyle it, open a small PR. You learn the architecture, and the team gets a readable map - everyone wins.

Demo 3 of 3

Make Nova clickable ★ 4 min · follow along

Last layer: links. Each Nova platform node gets a click-through to its (fictional) repo README - turning the overview diagram into a navigation hub for the whole platform.

flowchart LR
  ing[Ingestion] --> qa{Quality checks} --> dw[(Warehouse)]
  click ing "https://github.com/nova-platform/ingestion#readme" "Ingestion README"
  click qa "https://github.com/nova-platform/quality-checks#readme" "Quality checks README"
  click dw "https://github.com/nova-platform/warehouse#readme" "Warehouse README"

Take your Demo 1 source and add one click line per platform node, pointing at the repo README that owns it. Tooltip text in the second quotes.

Test in mermaid.live: hover shows the tooltip, click follows the link. Add _blank after the tooltip if you want a new tab.

Remember the deployment rule: clicks survive on mermaid.live, self-hosted pages, and most docs sites - but GitHub strips them. Keep a plain link list under the fence for GitHub readers.

Homework

Try it yourself - this week ◐ 30-45 min total

Source material

Official docs covered

This session teaches the working content of these sections of the flowchart page at mermaid.js.org (mermaid 11.x). Left with the official docs: the full 30+ shape catalog table and the animated-edge extras.

✓Flowchart: subgraphsPart 1 + Demos - blocks, nesting, direction, edges to zones
✓Flowchart: classDef, class, :::, style, linkStylePart 2 - the full styling toolkit with house rules
◐Flowchart: v11 expanded shapessyntax + handy names today; full catalog is a docs lookup
◐Flowchart: click interactionslinks + tooltips today; JS callbacks touched, deep dive in Session 6
Check yourself

Three questions before you go 🎯 ◐ 90 seconds

1 · Which line opens a subgraph you can later draw edges to by ID?

ID first, display title in brackets, close with end. The ID (plat) is what edges and class statements reference later.

2 · Six nodes need the same look. classDef or style?

classDef is CSS-thinking: define a meaning once, apply everywhere, change in one place. Six style lines is six future edits.

3 · Your flowchart hit 30 nodes and answers three different questions. Best move?

Styling cannot save a diagram that answers too many questions. One diagram, one question - link the family together.

Session 2 cheat sheet · pin this

Subgraphsubgraph id[Title] ... end. Always give the ID - edges and styles reference it. Nesting allowed.
Zone directiondirection TB/LR as the first line inside a subgraph - ignored if any inner node links outside the zone.
classDefclassDef name fill:#...,stroke:#...,color:#... - define all classes together at the bottom of the block.
Apply a classclass a,b,c name for lists · node[Label]:::name inline · style for a genuine one-off · linkStyle N for edge N (0-based).
Color disciplineClass names = meanings (stream, batch, deprecated), never looks. One meaning per color, always.
v11 shapesnode@{ shape: cyl, label: "..." } - named shapes: cyl, diam, stadium, hex, circle, rounded + 30 more in docs.
Clickclick id "url" "tooltip" (+ _blank for new tab). Works on live/self-hosted pages; GitHub strips it.
Split ruleOne diagram, one question. ~20+ nodes: find the seam. Overview map + linked zone details beats one hairball.