Free · No sign-up · Works with .mmd files

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 <|-- BankTransfer
Open this in the editor
Advertisement

Worked 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)
    }
Open in the editor

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 <|.. InMemoryRepository
Open in the editor

3. 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 issued
Open in the editor

4. 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~ <|-- UserRepository
Open in the editor

5. 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."
Open in the editor

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.

SyntaxMeaning
classDiagramOpens the diagram. Case-sensitive.
class Name { ... }Class with members. The closing brace goes on its own line.
+memberPublic.
-memberPrivate.
#memberProtected.
+method(Type arg) ReturnTypeA method — the parentheses are what make it one.
<<interface>> / <<abstract>>Stereotype annotation, written as the first line inside the class.
A <|-- BInheritance: B extends A.
A <|.. BRealisation: B implements interface A.
A *-- BComposition: B cannot outlive A.
A o-- BAggregation: B can exist without A.
A --> BAssociation with direction.
A ..> BDependency — A uses B but does not hold it.
A "1" --> "0..*" B : labelCardinality on each end plus a relationship label.
class Repo~T~Generic type parameter.
note for A "text"Note attached to a class.
direction LRChange layout direction.
Advertisement

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.

Broken
classDiagram
    class Order {
        +String id
Fixed
classDiagram
    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.

Broken
classDiagram
    Order ->> Customer
Fixed
classDiagram
    Order --> Customer : belongs to

What you see

No diagram type detected matching given configuration

Why

Wrong capitalisation of the keyword. `classdiagram` is not `classDiagram`.

Fix

Capitalise the D.

Broken
classdiagram
    class Order
Fixed
classDiagram
    class Order

What 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 `<|--`.

Broken
classDiagram
    CreditCard <|-- PaymentMethod
Fixed
classDiagram
    PaymentMethod <|-- CreditCard

What 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.

Broken
classDiagram
    class Repo {
        +save
        +find
    }
Fixed
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.

Broken
classDiagram
    Order o-- OrderLine : contains
Fixed
classDiagram
    Order *-- OrderLine : contains

Rendering 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:

Open the editor →