Mermaid class diagram editor
A class diagram shows types and how they relate: what contains what, what inherits from what, what depends on what. Use one when the shape of the code is the point — a domain model, a plugin interface, an inheritance tree. If you want to show what happens at runtime rather than how the types fit together, use a sequence diagram.
A payment domain model
Three relationship types in one diagram: composition for parts that cannot outlive the whole, inheritance for the payment method hierarchy, and a plain association with a cardinality label. The relationship arrows carry most of the meaning here — the class boxes are almost incidental.
classDiagram
class Order {
+String id
+OrderStatus status
+Money total()
+void addLine(Product p, int qty)
}
class OrderLine {
+Product product
+int quantity
+Money subtotal()
}
class PaymentMethod {
<<abstract>>
+authorise(Money amount) bool
}
class CreditCard {
+String last4
+authorise(Money amount) bool
}
class BankTransfer {
+String iban
+authorise(Money amount) bool
}
Order "1" *-- "1..*" OrderLine : contains
Order --> PaymentMethod : paid with
PaymentMethod <|-- CreditCard
PaymentMethod <|-- BankTransferWorked examples
1. One class
`+` is public, `-` is private, `#` is protected. A member with parentheses is rendered as a method; without them it is a field.
classDiagram
class User {
+String email
-String passwordHash
+bool verify(String candidate)
}2. Inheritance and interfaces
`<|--` is inheritance, read as "the one on the right extends the one on the left". The `<<interface>>` annotation is a label rather than a behaviour, but it is what makes the diagram readable.
classDiagram
class Repository {
<<interface>>
+find(String id) Entity
+save(Entity e) void
}
class PostgresRepository {
-Connection conn
+find(String id) Entity
+save(Entity e) void
}
class InMemoryRepository {
-Map store
+find(String id) Entity
+save(Entity e) void
}
Repository <|.. PostgresRepository
Repository <|.. InMemoryRepository3. Composition versus aggregation
The distinction is lifetime. A filled diamond (`*--`) means the part dies with the whole — delete the invoice and its lines are gone. A hollow diamond (`o--`) means the part survives independently.
classDiagram
class Invoice {
+String number
}
class InvoiceLine {
+String description
}
class Customer {
+String name
}
Invoice "1" *-- "1..*" InvoiceLine : composed of
Customer "1" o-- "0..*" Invoice : has issued4. Generics
Tildes give you type parameters: `Repository~User~`. Nesting works too, which is occasionally necessary and rarely a good idea.
classDiagram
class Repository~T~ {
+find(String id) T
+all() List~T~
}
class Cache~K, V~ {
+get(K key) V
+put(K key, V value) void
}
class UserRepository {
+findByEmail(String email) User
}
Repository~User~ <|-- UserRepository5. Notes and direction
`direction LR` lays the diagram out left-to-right, which usually suits an inheritance tree better than the default. A note is the right place for the constraint that does not fit in a class box.
classDiagram
direction LR
class EventStore {
+append(Event e) void
+replay(String streamId) List~Event~
}
class Snapshot {
+int version
+byte[] payload
}
EventStore --> Snapshot : writes every 100 events
note for EventStore "Append-only. Events are never mutated or deleted."Class diagram syntax reference
The relationship arrows are the part worth memorising — they are what distinguishes a class diagram from a box-and-line drawing, and they read right-to-left in a way that catches people out.
| Syntax | Meaning |
|---|---|
| classDiagram | Opens the diagram. Case-sensitive. |
| class Name { ... } | Class with members. The closing brace goes on its own line. |
| +member | Public. |
| -member | Private. |
| #member | Protected. |
| +method(Type arg) ReturnType | A method — the parentheses are what make it one. |
| <<interface>> / <<abstract>> | Stereotype annotation, written as the first line inside the class. |
| A <|-- B | Inheritance: B extends A. |
| A <|.. B | Realisation: B implements interface A. |
| A *-- B | Composition: B cannot outlive A. |
| A o-- B | Aggregation: B can exist without A. |
| A --> B | Association with direction. |
| A ..> B | Dependency — A uses B but does not hold it. |
| A "1" --> "0..*" B : label | Cardinality on each end plus a relationship label. |
| class Repo~T~ | Generic type parameter. |
| note for A "text" | Note attached to a class. |
| direction LR | Change layout direction. |
Errors that break class diagrams
Reproduced against Mermaid 11.12.2. Class diagrams are more forgiving than most types here, so several of these render happily and give you the wrong picture.
What you see
Parse error, ending in: got 'EOF_IN_STRUCT'
Why
A class body opened with `{` and never closed. The token name is unusually helpful for once — it means the file ended while still inside a class.
Fix
Close the brace on its own line.
classDiagram
class Order {
+String idclassDiagram
class Order {
+String id
}What you see
Parse error, ending in: got 'ANNOTATION_END'
Why
A sequence-diagram arrow used in a class diagram. `->>` means nothing here, and the parser gets far enough into it to produce a confusing token name.
Fix
Use a class relationship: `-->` for association, `<|--` for inheritance, `*--` for composition.
classDiagram
Order ->> CustomerclassDiagram
Order --> Customer : belongs toWhat you see
No diagram type detected matching given configuration
Why
Wrong capitalisation of the keyword. `classdiagram` is not `classDiagram`.
Fix
Capitalise the D.
classdiagram
class OrderclassDiagram
class OrderWhat you see
The arrow points the opposite way from what you meant
Why
Class relationship arrows are read from the arrowhead backwards. `A <|-- B` means B inherits from A, not the other way round. Written the wrong way it still renders — it just now claims your base class extends its own subclass.
Fix
Read it as "the far end extends the pointed end". Put the parent on the left of `<|--`.
classDiagram
CreditCard <|-- PaymentMethodclassDiagram
PaymentMethod <|-- CreditCardWhat you see
A field renders where you expected a method
Why
Parentheses are the only thing that distinguishes a method from a field. `+save` is a field named save; `+save()` is a method. Both are valid, so nothing warns you.
Fix
Add the parentheses, and the return type after them if you want it shown.
classDiagram
class Repo {
+save
+find
}classDiagram
class Repo {
+save(Entity e) void
+find(String id) Entity
}What you see
Composition and aggregation look the same at a glance and mean opposite things
Why
`*--` and `o--` differ by one character and encode a real semantic difference: whether the part can outlive the whole. Using the wrong one produces a diagram that is technically well-formed and factually wrong about your domain.
Fix
Filled diamond `*--` when deleting the parent deletes the child. Hollow `o--` when it does not.
classDiagram
Order o-- OrderLine : containsclassDiagram
Order *-- OrderLine : containsRendering notes
Measured against Mermaid 11.12.2 as this site runs it.
Class diagrams grow taller faster than any other type here
Three classes render to a viewBox of about 94×610. Forty classes render to 108×6900 — roughly 172 pixels of height per class, the steepest growth of the six types on this site. A forty-class diagram is nearly seven thousand pixels tall and unusable as a single image. `direction LR` helps, but past about fifteen classes the honest fix is to split the diagram by bounded context.
Member count barely affects width
Width is driven by the longest single member signature, not by how many members there are. A class with twenty short fields is no wider than one with three. This means you can be generous with members and stingy with classes, which is the opposite of most people's instinct.
Labels are HTML, so PNG export re-renders
Class labels are drawn inside an SVG `<foreignObject>`, which browsers refuse to rasterise onto a canvas. PNG export on this site used to fail silently and hand back an SVG file instead; it now re-renders the diagram with plain SVG text labels first. The PNG is correct and full size, with very slightly different typography from the screen.
Generics use tildes, and that has a consequence
`Repository~T~` exists because angle brackets would collide with HTML in labels. It also means a literal tilde in a class or member name will be read as the start of a type parameter. Rare, but genuinely confusing when it happens.
Theme changes colour, never layout
Default and dark themes produce an identical viewBox for the same source, so a class box cannot change size or clip its members when the theme changes.
When to use something else
If you are documenting a database rather than a type system, use an ER diagram. The distinction matters: class diagrams model behaviour and inheritance, which tables do not have, and ER diagrams model keys and cardinality properly, which class diagrams fudge.
If the diagram is mostly boxes with `-->` between them and no members, you are drawing an architecture diagram, not a class diagram. A flowchart with subgraphs will look better and imply less.
And if the class list is generated from code, consider whether the diagram should be too. A hand-maintained class diagram of a codebase that changes weekly is wrong within a month, and a wrong diagram costs more than no diagram.
Other diagram types
Written by Dominik Malsch · Last updated: