Mermaid Class Diagram: Complete Syntax Guide with Examples
Mermaid class diagrams let you document object-oriented design, data models, and system architecture in plain text that lives alongside your code. Write the structure once inside a Markdown file, and any Mermaid-compatible renderer — GitHub, VS Code, MacMD Viewer, or mermaid.live — produces a polished UML class diagram automatically. No diagramming app, no drag-and-drop, no file format incompatibilities.
TL;DR: Start with
classDiagram. Define classes withclass Name { +Type attr +method() Return }. Use visibility prefixes+,-,#,~. Connect classes with<|--(inheritance),*--(composition),o--(aggregation),-->(association). Annotate with<<Interface>>or<<Abstract>>. Preview locally with MacMD Viewer or at mermaid.live.
What Are Mermaid Class Diagrams Used For?
Mermaid class diagrams model the static structure of a codebase using UML notation. They answer three practical questions: what classes exist, what data and behavior each class owns, and how classes relate to each other. Developers reach for them in three contexts:
- OOP design — sketch the class hierarchy before writing code. Catch design problems like missing abstractions, circular dependencies, or bloated god classes before they are expensive to fix.
- API documentation — show the shape of request/response DTOs and domain objects so that consumers understand the contract without reading source files.
- System architecture — document service boundaries, shared models, and dependency direction in a format that non-engineers can read.
Unlike PlantUML, which requires a Java server or a browser plugin, Mermaid class diagrams render in any Markdown-aware environment that supports Mermaid — including GitHub READMEs natively since 2022. For local Markdown files on macOS, MacMD Viewer ($19.99) renders them offline with zero configuration.
How Do You Define a Class in Mermaid?
Every Mermaid class diagram starts with the keyword classDiagram. Classes are declared with the class keyword, followed by the name and an optional body in curly braces. Here is a minimal example:
classDiagram
class Animal {
+String name
+int age
+makeSound() String
#breathe() void
-heartRate int
}The body lists attributes and methods. Attributes follow the format visibility Type name. Methods follow the format visibility name(params) ReturnType. Visibility is specified with a single character prefix:
| Prefix | Visibility | UML Equivalent |
|---|---|---|
+ | Public | Open circle |
- | Private | Closed circle |
# | Protected | Hash |
~ | Package / Internal | Tilde |
Two special suffixes modify member semantics:
$— static member (e.g.,+getInstance()$ Instance)*— abstract method (e.g.,+makeSound()* String)
If you do not need to list members, you can declare a class in one line and define it inline in a relationship. But explicit class bodies make the diagram self-documenting and eliminate guesswork about what each class contains.
What Relationship Types Does Mermaid Support?
Relationships are the most important part of any class diagram. Mermaid supports eight relationship types, each corresponding to a standard UML arrow. Choosing the correct one is critical — using composition where aggregation is appropriate, or association where dependency fits better, produces diagrams that mislead readers about how the system actually works.
| Arrow | Syntax | Relationship | Meaning |
|---|---|---|---|
| Inheritance | <|-- | Is-a | Child extends Parent |
| Composition | *-- | Has-a (strong) | Child cannot exist without Parent |
| Aggregation | o-- | Has-a (weak) | Child can exist independently |
| Association | --> | Uses | One class knows about another |
| Link (solid) | -- | Related | General undirected connection |
| Dependency | ..> | Depends-on | Uses temporarily (parameter, return) |
| Realization | ..|> | Implements | Class fulfills an interface contract |
| Bidirectional | <--> | Both directions | Mutual awareness |
Here is a diagram showing all eight relationship types:
classDiagram
class Vehicle
class Car
class Engine
class Wheel
class Driver
class Fuel
class Printable
class Report
Car <|-- Vehicle : inherits
Car *-- Engine : composition
Car o-- Wheel : aggregation
Car --> Driver : association
Car -- Fuel : link
Report ..> Car : dependency
Report ..|> Printable : realization
Driver <--> Car : bidirectionalA few rules prevent the most common mistakes:
- Inheritance
<|--— the closed arrowhead always points toward the parent. WriteDog <|-- Animalmeans Dog inherits Animal, which is wrong. WriteAnimal <|-- Dogto express that Dog extends Animal. - Composition
*--— the filled diamond is on the owner's side.Order *-- OrderItemmeans Order owns OrderItems; destroying the Order destroys its items. - Realization
..|>— the open arrowhead points toward the interface, not the implementing class.Serializable ..|> Reportmeans Serializable implements Report, which is backwards. WriteReport ..|> Serializable.
How Do You Add Cardinality Labels?
Cardinality labels describe how many instances participate in a relationship. Place them in quotes adjacent to each end of the relationship arrow:
classDiagram
class Customer {
+String email
+placeOrder() Order
}
class Order {
+DateTime createdAt
+calculateTotal() float
}
class OrderItem {
+int quantity
+float unitPrice
}
Customer "1" --> "0..*" Order : places
Order "1" *-- "1..*" OrderItem : containsCommon cardinality notations:
| Notation | Meaning |
|---|---|
"1" | Exactly one |
"0..1" | Zero or one (optional) |
"1..*" | One or more |
"0..*" or "*" | Zero or more |
"n" | Exactly n |
Cardinality labels appear directly on the rendered arrow, making the multiplicity obvious without any accompanying prose. Use them on any relationship where the count is meaningful — especially compositions and associations in domain models.
How Do You Use Annotations for Interfaces, Abstract Classes, and Enumerations?
Annotations apply UML stereotypes to a class. They render as a label in double angle brackets above the class name and visually distinguish special class types from concrete implementations:
classDiagram
class PaymentMethod {
<<Interface>>
+pay(amount float) bool
+refund(amount float) bool
+getTransactionId() String
}
class AbstractNotifier {
<<Abstract>>
+String recipient
+send(message String)* void
+formatMessage(content String) String
}
class PaymentStatus {
<<Enumeration>>
PENDING
COMPLETED
FAILED
REFUNDED
}
class PaymentService {
<<Service>>
+processPayment(method PaymentMethod, amount float) bool
}The four most common annotations and when to use them:
| Annotation | Use Case |
|---|---|
<<Interface>> | Pure contract — no implementation, only method signatures |
<<Abstract>> | Partial implementation — some methods are abstract (*) |
<<Enumeration>> | Fixed set of named constants |
<<Service>> | Stateless business logic class (DDD or Spring convention) |
You can also add notes to specific classes using the note keyword:
note for PaymentMethod "All payment methods must implement this interface"
Notes render as callout boxes attached to the class in the diagram output.
How Do You Use Namespaces to Organize Large Diagrams?
When a diagram covers multiple packages or modules, namespace blocks group related classes under a labeled boundary:
classDiagram
namespace Domain {
class Product {
+String name
+float price
+int stock
}
class Category {
+String label
}
}
namespace Application {
class ProductService {
<<Service>>
+findById(id String) Product
+updateStock(id String, delta int) void
}
}
Product --> Category : belongsTo
ProductService ..> Product : dependencyNamespace boundaries appear as labeled rectangles in the rendered output. They are purely visual — they do not change how relationships are drawn, and arrows can cross namespace boundaries freely. Use them whenever a diagram spans more than one layer or bounded context.
Real Example: E-Commerce OOP Design
The best way to learn class diagram syntax is to read a complete, realistic example. The following diagram models the core domain of an e-commerce system: users, products, carts, orders, and payments.
classDiagram
class User {
+String id
+String email
+String passwordHash
+DateTime createdAt
+register(email String, password String) User$
+authenticate(password String) bool
+getCart() Cart
}
class Product {
+String id
+String name
+float price
+int stockLevel
+String categoryId
+isInStock() bool
+applyDiscount(pct float) void
}
class Cart {
+String id
+DateTime updatedAt
+addItem(product Product, qty int) void
+removeItem(productId String) void
+calculateTotal() float
+checkout() Order
}
class CartItem {
+int quantity
+float unitPrice
+getSubtotal() float
}
class Order {
+String id
+DateTime placedAt
+OrderStatus status
+float totalAmount
+confirm() void
+cancel() void
+getItems() CartItem[]
}
class Payment {
<<Interface>>
+pay(amount float) bool
+refund(amount float) bool
+getTransactionId() String
}
class CreditCardPayment {
+String cardLastFour
+String cardToken
+pay(amount float) bool
+refund(amount float) bool
+getTransactionId() String
}
class OrderStatus {
<<Enumeration>>
PENDING
CONFIRMED
SHIPPED
DELIVERED
CANCELLED
}
User "1" --> "1" Cart : owns
Cart "1" *-- "0..*" CartItem : contains
CartItem "0..*" --> "1" Product : references
Cart --> Order : checkout creates
Order "1" *-- "1..*" CartItem : includes
Order --> Payment : paid via
CreditCardPayment ..|> Payment : implements
Order --> OrderStatus : has statusWalking through the key design decisions in this diagram:
Cart *-- CartItem— composition, because CartItems have no meaning outside their Cart.CartItem --> Product— association with"0..*"to"1", because a Product can appear in many carts but a CartItem references exactly one Product.Cart --> Order— association with a label clarifying the relationship's intent (checkout creates).CreditCardPayment ..|> Payment— realization, because CreditCardPayment implements the Payment interface contract.<<Enumeration>>onOrderStatus— communicates that this is a fixed set of states, not a free-form class.
This diagram communicates the entire domain model to a new team member in under a minute. Adding a second payment method (e.g., PayPalPayment) requires one new class and one ..|> realization line — the interface design makes extension obvious.
What Are Common Mistakes in Mermaid Class Diagrams?
Several mistakes appear regularly when developers first adopt Mermaid class diagrams. Knowing them upfront saves debugging time.
Reversed inheritance arrow. Animal <|-- Dog reads as "Animal inherits Dog," which is wrong. The arrowhead points toward the parent. The correct syntax is Dog <|-- Animal (Animal is the parent, Dog is the child that extends it). If you think of it as "Dog is-a Animal," the arrow flows from Dog toward Animal.
Missing visibility prefix. Writing String name inside a class body without a prefix (+, -, #, ~) is valid syntax but produces no visibility indicator in the output. Omitting visibility makes diagrams less informative and harder to distinguish from pseudocode.
Confusing composition and aggregation. Use *-- (composition) only when the child's lifecycle is tied to the parent — deleting the parent deletes the children. Use o-- (aggregation) when the child can survive independently. Library *-- Book is wrong if books can be moved to another library. Library o-- Book is correct.
Realization arrow pointing the wrong way. ..|> points toward the interface, not toward the implementor. Printable ..|> Report says the interface implements the class, which is backwards. Write Report ..|> Printable.
Putting return type before method name. Mermaid uses the format +methodName(params) ReturnType — the return type comes last. Writing +String getName() (Java style) breaks the syntax.
Mermaid Class Diagrams vs. PlantUML
Both tools produce UML class diagrams from text. The choice depends on where your diagrams live.
| Feature | Mermaid | PlantUML |
|---|---|---|
| Rendering | Browser-native, GitHub-native | Requires Java server or online service |
| Syntax | Lightweight, close to pseudocode | More verbose, closer to formal UML |
| Markdown integration | Native (code fence) | Requires plugin or preprocessing |
| Class diagram depth | Covers most UML class features | Full UML 2.x support |
| Namespace support | Yes (namespace keyword) | Yes (package keyword) |
| Notes/stereotypes | Limited but functional | More options |
| Offline rendering on Mac | MacMD Viewer, VS Code | PlantUML VS Code extension |
For most engineering teams using GitHub, Notion, or Confluence for documentation, Mermaid is the pragmatic choice: zero tooling overhead, native rendering in the platforms you already use. See our Mermaid diagrams in Confluence guide for setup steps.
For teams that need the full UML 2.x specification with advanced features like lifeline constraints or object diagrams, PlantUML provides more depth — at the cost of additional infrastructure.
How Do You Preview Mermaid Class Diagrams?
Four options cover every workflow:
- MacMD Viewer ($19.99) — open any
.mdfile containing aclassDiagramand the diagram renders instantly. Native SwiftUI, works offline, 2 MB on disk. The bundled QuickLook extension lets you press Space in Finder to preview diagrams without opening the app. See the Mermaid viewer feature page for details. Available on the /download page. - Mermaid Live Editor — paste your syntax and see the output side by side. Export as SVG or PNG. Best for iteration before committing to a file. See our Mermaid Live Editor guide for tips.
- VS Code — install the Markdown Mermaid extension, open any
.mdfile, and pressCmd+Shift+Vto render all diagrams in the preview pane. - GitHub — push a
.mdfile with a```mermaidfence and GitHub renders the class diagram natively on the repository page.
For a comparison of browser-based Mermaid tools, see online Mermaid diagram tools.
Conclusion
Mermaid class diagram syntax covers the full OOP design surface: classes with typed attributes and methods, eight relationship types with cardinality labels, visibility modifiers, annotations for interfaces and abstract classes, namespace grouping, and notes. The text lives in version control alongside the code it documents, so diagrams stay accurate as the codebase evolves.
Start with the e-commerce example above. Replace the class names and members with your own domain model, run it through MacMD Viewer or mermaid.live, and you have production documentation in under ten minutes. For other Mermaid diagram types, see the flowchart syntax guide, sequence diagram guide, and ER diagram guide.
Continue reading with AI
Content licensed under CC BY 4.0. Cite with attribution to MacMD Viewer.