PlantUML Class Diagram: Relationships, Syntax, and Examples

··Updated ·6 min read
plantumlclass-diagramumldomain-modeling

A PlantUML class diagram describes the static structure of a system: types, members, and relationships. You write declarations and connectors as text, then let PlantUML lay out the result. This tutorial develops an e-commerce model to explain visibility, inheritance, implementation, dependency, aggregation, composition, and multiplicity.

For a gallery of other diagram types, begin with PlantUML examples. If your main concern is behavior over time, the PlantUML sequence diagram guide is the better starting point.

Key Takeaways

  • Class diagrams answer “what exists and how is it related?” rather than “what happens next?”
  • <|--, <|.., *--, o--, and ..> encode different relationship semantics.
  • Composition and aggregation should reflect lifecycle ownership, not visual preference.
  • Quoted labels at relationship ends express multiplicity such as "1" and "0..*".
  • PlantUML renders a model but cannot determine whether the model is correct for your domain.

Prerequisites

Open the OnUML editor, choose PlantUML mode, and paste each example into the source editor. OnUML generates the preview in the browser workflow, so no local renderer or programming language is required. Sign in and save the OnUML project when you want to continue editing it later. The examples follow the official PlantUML class diagram documentation, retrieved July 24, 2026.

Step 1: Define a Class with Fields and Methods

Place members inside braces. Visibility symbols are + for public, - for private, # for protected, and ~ for package-private visibility.

@startuml
class Product {
  -id: UUID
  -name: String
  -price: Money
  +changePrice(newPrice: Money): void
  +isAvailable(): Boolean
}
@enduml

The notation documents design intent; it does not generate or inspect application code by itself. Choose a consistent member format and avoid filling the diagram with accessors that add no architectural information.

Step 2: Add Interfaces, Abstract Classes, and Enums

PlantUML has dedicated declarations for interface, abstract class, and enum. Use them when the distinction helps readers understand substitutability or constrained values.

@startuml
interface PaymentGateway {
  +authorize(amount: Money): Authorization
  +capture(id: UUID): Receipt
}

abstract class Payment {
  #amount: Money
  +process(): PaymentResult
}

class CardPayment
class BankTransfer

enum PaymentStatus {
  PENDING
  AUTHORIZED
  CAPTURED
  FAILED
}

Payment <|-- CardPayment
Payment <|-- BankTransfer
PaymentGateway <|.. CardPayment
Payment --> PaymentStatus
@enduml

<|-- points from a subtype toward its parent. <|.. uses a dotted line for interface realization. Keep arrow direction consistent across the article or project so readers do not need to reinterpret each view.

Step 3: Choose the Correct Relationship

Relationships should communicate domain meaning:

PlantUML syntaxTypical meaningDecision question
`Parent <-- Child`Inheritance
`Interface <.. Type`Interface implementation
Whole *-- PartCompositionDoes the part's lifecycle depend on the whole?
Whole o-- PartAggregationCan the part exist independently?
A --> BDirected associationDoes A retain or navigate to B?
A ..> BDependencyDoes A temporarily use B?

The official class diagram guide distinguishes composition from aggregation by whether the part can exist independently of the whole. Real domains can still be ambiguous. For example, an order line may be composed into an order, while a product referenced by that line exists independently.

@startuml
class Order
class OrderLine
class Product
class PricingService

Order "1" *-- "1..*" OrderLine : contains
OrderLine "*" --> "1" Product : references
Order ..> PricingService : requests price from
@enduml

Step 4: Express Multiplicity

Put multiplicity labels in quotes next to each endpoint. Common values include "1", "0..1", "*", and "1..*".

@startuml
class Customer
class Address
class Order
class OrderLine
class Product

Customer "1" o-- "0..*" Address : stores
Customer "1" --> "0..*" Order : places
Order "1" *-- "1..*" OrderLine : contains
OrderLine "*" --> "1" Product : selects
@enduml

Read Order "1" *-- "1..*" OrderLine as one order owning one or more lines. The symbol describes the proposed model, not a checked database constraint. If storage rules are the main purpose of the document, use PlantUML ER diagram entities and cardinality.

Step 5: Organize a Larger Domain

Packages reduce visual overload and communicate boundaries. The following complete model separates ordering, catalog, and payment concepts.

@startuml
title E-commerce domain model
left to right direction

package Ordering {
  class Customer {
    +id: UUID
    +email: String
  }

  class Order {
    +number: String
    +status: OrderStatus
    +total(): Money
  }

  class OrderLine {
    +quantity: Integer
    +unitPrice: Money
    +subtotal(): Money
  }

  enum OrderStatus {
    DRAFT
    PLACED
    PAID
    CANCELLED
  }
}

package Catalog {
  class Product {
    +sku: String
    +name: String
    +price: Money
  }
}

package Payments {
  interface PaymentGateway {
    +authorize(orderId: UUID, amount: Money): Authorization
  }

  class CheckoutService {
    +checkout(order: Order): Receipt
  }
}

Customer "1" --> "0..*" Order : places
Order "1" *-- "1..*" OrderLine : contains
OrderLine "*" --> "1" Product : references
Order --> OrderStatus
CheckoutService ..> Order : processes
CheckoutService ..> PaymentGateway : uses
@enduml

This diagram deliberately omits controllers, repositories, and framework classes. A domain view is more useful when it emphasizes business concepts. Create a separate implementation view if infrastructure choices are the actual review topic.

How Do Class Diagrams Relate to C4 Diagrams?

A class diagram zooms into type-level structure. A C4 diagram usually starts higher, showing people, systems, containers, and components. Use the PlantUML C4 architecture guide when stakeholders need boundaries and responsibilities before they need classes.

For runtime interaction between CheckoutService and PaymentGateway, link this static view to the PlantUML sequence diagram tutorial. Two small connected diagrams are often clearer than one overloaded diagram.

Common Class Diagram Mistakes

ProblemConsequenceFix
Composition is used for every strong relationshipLifecycle ownership becomes meaninglessAsk whether the part survives the whole
Every code member is listedThe diagram becomes an unreadable code dumpInclude only members relevant to the view
Multiplicity is missingReaders invent different cardinalitiesLabel both ends when counts matter
Dependencies and associations are mixedTemporary use looks like retained stateUse ..> for a dependency
Packages mirror folders blindlyTechnical layout replaces domain meaningGroup around the question being reviewed
The rendered diagram is treated as proofIncorrect modeling gains false authorityValidate with domain and implementation owners

Frequently Asked Questions

What is the difference between *-- and o--?

*-- represents composition, where the part's lifecycle depends on the whole. o-- represents aggregation, where the part can exist independently. The right choice depends on domain lifecycle semantics.

How do I show a Java interface implementation?

Declare an interface, declare the implementing class, and connect them with <|.., pointing toward the interface.

@startuml
interface Repository
class SqlRepository
Repository <|.. SqlRepository
@enduml

Can PlantUML generate classes from my diagram?

PlantUML's documented role is rendering diagrams from text. Code generation or reverse engineering depends on separate tools and integrations, so verify the capabilities of the exact toolchain you use.

Where can I compare Mermaid and PlantUML class diagrams?

See the existing Mermaid vs PlantUML class diagram comparison when choosing a diagram language.

Next Steps

Copy the e-commerce example and remove every type that does not help answer your current design question. Then confirm multiplicity and lifecycle ownership with someone who understands the domain.

Continue with the PlantUML examples hub, the sequence diagram guide, or PlantUML C4 diagrams. The official class diagram reference documents additional syntax for generics, notes, namespaces, and advanced display options. PlantUML's common commands reference covers titles, captions, legends, headers, and footers that can be shared across diagram types.

If the review question concerns concrete runtime instances rather than type definitions, compare the model with PlantUML's official object diagram guidance before adding instance data to a class diagram.