PlantUML to Mermaid
PlantUML to Mermaid converter (sequence and class diagrams)
In short
Paste a PlantUML sequence or class diagram and get the equivalent Mermaid code: participants, every arrow style, activations, alt/loop/opt/par fragments and notes for sequences; classes with members, stereotypes, generics, every relationship arrow and multiplicities for class diagrams. The conversion is a plain text transform in your browser. Constructs Mermaid cannot express are not silently lost — each one is listed in the conversion notes as dropped or approximated.
Mermaid code
Live preview
Conversion notes
| Line | PlantUML construct | Result | What happened |
|---|
Runs in your browser — nothing is uploaded. The live preview downloads the Mermaid library (about 2.5 MB) from esm.sh on first use and renders locally.
Updated · by the ChartCraft team
How does PlantUML sequence syntax map to Mermaid?
Most sequence constructs have a direct equivalent; the differences are in the arrows (Mermaid distinguishes line style and head shape with different characters), in participant declaration order (participant alias as Label in Mermaid, the reverse of PlantUML), and in a handful of PlantUML-only features — dividers, delays, return, messages from outside the diagram — which the converter approximates or drops and reports.
| Construct | PlantUML | Mermaid | Converter | |
|---|---|---|---|---|
| Diagram wrapper | @startuml … @enduml | sequenceDiagram | Converted | |
| Title | title Checkout flow | ---
title: Checkout flow
--- front-matter | Converted | |
| Participant with label | participant "Web app" as W | participant W as Web app | Converted (order swapped) | |
| Actor | actor "Shopper" as U | actor U as Shopper | Converted | |
| Boundary / control / entity / database / collections / queue | database "Orders" as D | participant D as Orders | Approximated — Mermaid has only participant and actor | |
| Synchronous message | A -> B : msg | A->>B: msg | Converted (solid line, filled head) | |
| Reply / dotted | A --> B : msg | A-->>B: msg | Converted | |
| Thin / asynchronous head | A ->> B : msg | A-)B: msg | Converted (open head = async in Mermaid) | |
| Dotted asynchronous | A -->> B : msg | A--)B: msg | Converted | |
| Reversed arrow | A <- B : msg | B->>A: msg | Converted (sender and receiver swapped) | |
| Lost message | A ->x B : msg | A-xB: msg | Converted | |
| Circle / half heads | A ->o B | , A -\\ B | A->>B | Approximated — drawn with a normal head |
| Coloured arrow | A -[#red]> B : msg | A->>B: msg | Approximated — colour dropped | |
| Activation | activate A / deactivate A | activate A / deactivate A | Converted | |
| Activation shortcuts | A -> B ++ : call, B -> A -- : done | A->>+B: call, B->>-A: done | Converted | |
return | return result | B-->>-A: result | Converted using the open activation; approximated if none is open | |
| Create / destroy | create B, destroy B, A -> B ** : new | create participant B, destroy B | Converted (Mermaid ≥ 10.3) | |
| Alternatives | alt cond … else cond … end | alt cond … else cond … end | Converted | |
| Loop / optional / break | loop 3 times … end, opt … end, break … end | same syntax | Converted | |
| Parallel | par … else … end | par … and … end | Converted (else becomes and) | |
| Critical region | critical … else … end | critical … option … end | Converted | |
| Group | group My label … end | rect rgb(245,243,238) … end | Approximated — Mermaid has no labelled group | |
| Note on a participant | note left of A : text, note right of A … end note | Note left of A: text (lines joined with <br/>) | Converted | |
| Note over participants | note over A, B : text | Note over A,B: text | Converted | |
| Note on the previous message | note left : text | Note left of <receiver>: text | Approximated — attached to the participant | |
| Divider | == Phase 2 == | Note over First,Last: Phase 2 | Approximated — Mermaid has no divider | |
| Reference | ref over A, B : see X | Note over A,B: ref: see X | Approximated | |
| Autonumber | autonumber, autonumber 10 5 | autonumber | Converted; start/step/format dropped | |
| Box around participants | box "Backend" #LightBlue … end box | box Backend … end | Converted; colour dropped | |
| Delay / spacing | ..., ...5 min later..., ||| | — | Dropped | |
| Messages from outside | [-> A : request, A ->] : done | — | Dropped | |
| Comments | ' text, /' block '/ | %% text | Converted / block comments dropped | |
| Styling | skinparam …, hide footbox, !theme, !include | — | Dropped |
sequenceDiagram
autonumber
actor U as Shopper
participant W as Web app
participant P as Payment API
U->>W: Place order
activate W
W->>+P: POST /charge
alt card accepted
P-->>-W: 200 OK
else card declined
P-->>W: 402 Payment Required
end
W--)U: Show confirmation
deactivate W
How does PlantUML class syntax map to Mermaid?
The relationship arrows are nearly identical in the two languages, and multiplicities use the same quoted-string form. The real differences are in members — PlantUML writes name : type, Mermaid writes type name and marks static/abstract with a $/* suffix — and in kinds: Mermaid has only class, so interfaces, abstract classes and enums become stereotype annotations such as <<interface>>.
| Construct | PlantUML | Mermaid | Converter |
|---|---|---|---|
| Diagram wrapper | @startuml … @enduml | classDiagram | Converted |
| Class with body | class Account {
-balance : double
+deposit(amount : double) : void
} | class Account {
-double balance
+deposit(double amount) void
} | Converted — members re-ordered to type-first |
| Abstract class | abstract class Shape | class Shape {
<<abstract>>
} | Converted |
| Interface | interface Drawable | class Drawable {
<<interface>>
} | Converted |
| Enum | enum Color { RED, GREEN } | class Color {
<<enumeration>>
RED
GREEN
} | Converted |
| Stereotype | class Order <<entity>> | <<entity>> inside the body | Converted; spot letter and colour dropped |
| Display name | class "Shopping cart" as Cart | class Cart["Shopping cart"] | Converted |
| Generics | class Repo<T> | class Repo~T~ | Converted |
| Static / abstract member | {static} +count : int, {abstract} +run() | +int count$, +run()* | Converted |
| Visibility | + - # ~ | + - # ~ | Same in both |
extends / implements | class Dog extends Animal implements Pet | Animal <|-- Dog, Pet <|.. Dog | Converted to relationship lines |
| Inheritance | Animal <|-- Dog | same syntax | Same |
| Realization | Pet <|.. Dog | same syntax | Same |
| Composition | Car *-- Engine | same syntax | Same |
| Aggregation | Team o-- Player | same syntax | Same |
| Association / dependency | A --> B, A ..> B, A -- B | same syntax | Same |
| Reversed arrows | Dog --|> Animal, Engine --* Car | same syntax | Same |
| Multiplicities and labels | Order "1" *-- "many" Item : contains | same syntax | Same |
| Label direction marker | A --> B : uses > | A --> B : uses | Approximated — the > / < marker is dropped |
| Direction hints | A -down-> B, A -[hidden]- B | A --> B | Approximated — hint dropped |
| Member outside the body | Account : +close() | added to the class body | Converted |
| Package / namespace | package billing { … } | namespace billing { … } | Approximated — classes grouped; relations stay outside |
| Layout direction | left to right direction | direction LR | Converted |
| Note on a class | note left of A : text | note for A "text" | Approximated — side is ignored |
| Note on a relation | A --> B
note right : text | — | Dropped |
| Body separators | --, .. | — | Dropped |
| Nesting, lollipops, crow's feet | A +-- B, A ()-- B, A }-- B | A -- B | Approximated — plain line |
| Styling | skinparam …, hide empty members, #colour | — | Dropped |
classDiagram
class Shape {
<<abstract>>
+String name
+area() double
}
class Drawable {
<<interface>>
+draw() void
}
class Circle {
-double radius
+area() double
}
Shape <|-- Circle
Drawable <|.. Circle
Canvas "1" o-- "*" Shape : contains
What do "dropped" and "approximated" mean in the conversion notes?
Every line of PlantUML that does not have an exact Mermaid equivalent produces one row in the notes table, with its line number, so you can check the result against the original instead of trusting it blindly.
| Result | Meaning | What to do |
|---|---|---|
| converted | The construct exists in both languages with a different spelling; the meaning is preserved. | Nothing. |
| approximated | Mermaid has no exact equivalent; the closest construct was used (a divider became a spanning note, a database participant became a plain participant, a package became a namespace). | Read the output once; adjust by hand if the approximation misleads. |
| dropped | No Mermaid equivalent and no sensible stand-in: delays, messages from outside the diagram, skinparam styling, notes on relations, body separators. | Re-add styling with Mermaid %%{init}%% directives or classDef if you need it. |
The converter covers the sequence and class subsets above. PlantUML activity, use-case, state, component and deployment diagrams are not converted; for those, describe the diagram in words in the AI diagram generator, or compare the two languages feature by feature on the PlantUML alternative and Mermaid alternative pages. A compact syntax reference for the output is the Mermaid cheat sheet.
Questions
Does the converter cover every PlantUML feature?
No — it covers the sequence and class diagram subsets listed in the two mapping tables, which is what most READMEs and design docs use. Every construct outside that subset is reported in the conversion notes as dropped or approximated with its line number, so nothing disappears silently. Activity, use-case, state, component and deployment diagrams are not converted.
Why do PlantUML's --> and Mermaid's --> mean different things?
In a PlantUML sequence diagram --> is a dotted (reply) arrow with a filled head; in Mermaid the same spelling is a dotted line with no head, and the filled-head reply is -->>. The converter maps by meaning: PlantUML -> becomes ->>, --> becomes -->>, and the thin PlantUML head ->> becomes Mermaid's open async head -).
Is the conversion done by an AI model?
No. It is a deterministic text transform — a few hundred lines of JavaScript that run in your browser — so the same input always gives the same output, nothing is sent to a server, and it works offline once the page has loaded. The preview uses the standard Mermaid library.
Why does the live preview need a 2.5 MB download?
The preview is rendered by the real Mermaid library (version 11) so that what you see is what GitHub, Notion or your docs site will draw. It is loaded from esm.sh only when you click Render preview or tick auto-render, and cached by the browser afterwards. The code conversion itself needs nothing extra.
What happens to multi-line notes and \n in messages?
Multi-line note … end note blocks are joined with <br/>, which Mermaid renders as line breaks. A literal \n inside a PlantUML message is converted to <br/> as well.
My participant names have spaces — will that break Mermaid?
No. Mermaid needs a single-token id for each participant, so "Order Service" -> "Mail Service" becomes participant Order_Service as Order Service and the message uses the alias; the label on the diagram keeps the spaces.
Can I convert Mermaid back to PlantUML?
Not on this page — it converts in one direction. For a diagram you want to keep editing without either syntax, open it in the ChartCraft studio, where you describe changes in plain English and export SVG or PNG; see the sequence and class diagram generators linked below.
Which Mermaid version is the output written for?
Mermaid 10.3 or newer. The output uses front-matter titles, create participant/destroy, box, critical … option, namespace and class X["label"], which older Mermaid (9.x and early 10.x) did not support. GitHub, GitLab, Notion and Obsidian all ship a recent version.