When you're designing a system made up of independent services, the biggest challenge isn't writing the code it's making sure every team understands how the pieces fit together. A UML class diagram code example for microservices architecture gives developers, architects, and stakeholders a shared visual language. It maps out service boundaries, data models, and communication contracts before anyone writes a single line of production code. Without it, teams often build services that overlap in responsibility, share data they shouldn't, or break each other's APIs with every sprint.
What does a UML class diagram for microservices actually show?
A UML class diagram in this context does something different than a traditional class diagram for a monolith. Instead of showing every internal class of one application, it focuses on service boundaries, domain models per service, and the interfaces or DTOs that services expose to each other. Each microservice typically becomes a UML package or namespace, and the classes inside represent the core domain entities, repositories, and service-layer objects within that boundary.
Arrows and associations between packages represent API calls, message queues, or event-driven communication. This makes the diagram useful for answering questions like: which service owns the Order entity? Can the PaymentService directly access Customer data, or does it go through an API? These are the kinds of questions that prevent costly architectural mistakes.
When should you create one?
You don't need a full UML class diagram for every feature. But there are clear moments when it pays off:
- Starting a new microservices project when defining domain boundaries and service ownership for the first time.
- Refactoring a monolith when splitting a single codebase into services and you need to track which classes belong where.
- Designing cross-service APIs when multiple teams need to agree on shared DTOs, request/response payloads, and event schemas.
- Onboarding new developers when someone needs to understand the system without reading every repository.
- Architecture reviews when you need a visual artifact to discuss coupling, shared databases, or circular dependencies.
What does the code look like? A practical example
Let's say you have three microservices: OrderService, InventoryService, and NotificationService. Here's how you'd represent them in UML diagram markup:
Using PlantUML syntax, a simplified version looks like this:
@startuml
package "OrderService" {
class Order {
- orderId: String
- customerId: String
- items: List<OrderItem>
- status: OrderStatus
+ placeOrder(): OrderResult
+ cancelOrder(orderId): boolean
}
class OrderItem {
- productId: String
- quantity: int
- price: BigDecimal
}
class OrderRepository {
+ save(order: Order): void
+ findById(orderId: String): Order
}
Order --> OrderItem
OrderRepository --> Order
}
package "InventoryService" {
class Product {
- productId: String
- name: String
- stockCount: int
+ reserveStock(quantity: int): boolean
+ releaseStock(quantity: int): void
}
class InventoryRepository {
+ findByProductId(productId: String): Product
+ updateStock(product: Product): void
}
InventoryRepository --> Product
}
package "NotificationService" {
class Notification {
- notificationId: String
- recipientId: String
- type: NotificationType
- message: String
+ send(): boolean
}
}
interface "OrderEvent" {
+ orderId: String
+ eventType: String
}
Order ..> OrderEvent : publishes
Notification ..> OrderEvent : subscribes
@enduml
This diagram makes a few things immediately clear. The Order entity lives inside OrderService no other service should store it. The communication between OrderService and NotificationService happens through an OrderEvent interface, not a direct API call. InventoryService doesn't need to know about Order internals; it only cares about productId and quantity.
How do service boundaries look different from monolith diagrams?
In a monolith UML class diagram, you might see hundreds of classes with dense associations. In a microservices diagram, the emphasis shifts to loose coupling between packages and strong cohesion within them.
Here are the key structural differences:
- Packages represent services, not modules within a single application.
- Interfaces and DTOs sit at the boundary of each package, acting as the contract between services.
- Direct associations between classes in different packages should be rare. If you see them, it's a sign of tight coupling.
- Shared database tables are flagged explicitly using dependency stereotypes like
<<shared DB>>or shown as a separate package with a warning. - Event-driven patterns use dashed arrows to interfaces rather than solid lines between classes.
You can explore different markup approaches in this guide to UML diagram markup tools to find what fits your team's workflow.
What mistakes do teams make with these diagrams?
After working with microservices architectures for a while, certain patterns repeat as mistakes:
- Drawing every internal class Your microservice diagram doesn't need every utility class, helper, or infrastructure layer detail. Focus on domain models and service interfaces. Internal implementation details change too frequently to maintain in a diagram.
- Ignoring the communication style A solid line between two service classes hides whether the call is synchronous REST, asynchronous messaging, or gRPC. Use stereotypes or notes like
<<REST>>,<<Kafka>>, or<<gRPC>>to make this explicit. - Letting diagrams go stale A diagram that doesn't match the codebase is worse than no diagram at all. Treat it like code: version it, review it, and update it when services change.
- Using one giant diagram for the whole system Once you have more than 5–7 services, one diagram becomes unreadable. Create per-domain or per-bounded-context diagrams and link them.
- Showing database schemas instead of domain models Your class diagram should represent the domain as your services understand it, not a one-to-one mapping of database tables. ORM entities and domain objects aren't always the same thing.
How do you handle cross-service data references?
This is one of the trickiest parts of microservices design, and your UML diagram should reflect the solution you chose. There are three common patterns:
API composition Service A calls Service B's API to get data it needs. In the diagram, this shows as a dependency from a service class to a remote interface.
Event-driven data replication Service B publishes events, and Service A maintains a local read model. In the diagram, you'd show a local CustomerReadModel class inside OrderService with a dashed dependency to a CustomerEvent interface.
Shared nothing Services only reference each other by ID. The diagram shows customerId: String on the Order class but no direct association to a Customer class. This is the cleanest pattern and should be your default.
If you need to document how these cross-service flows execute over time, a UML sequence diagram complements your class diagram well. The class diagram shows structure; the sequence diagram shows behavior.
What tools work best for writing these diagrams as code?
Writing UML as code (text-based markup) has real advantages for microservices projects: diagrams live in the same repository as the code, they're diffable in pull requests, and they don't require expensive desktop software. Common options include:
- PlantUML the most widely adopted text-based UML tool. It supports class diagrams, sequence diagrams, deployment diagrams, and more. Rendering happens locally or via their web server.
- Mermaid built into GitHub, GitLab, and many documentation platforms. Slightly less expressive than PlantUML for complex class diagrams but very convenient.
- Structurizr DSL designed specifically for software architecture diagrams including C4 model views. Good for microservices when you want to zoom between system-level and code-level views.
- D2 a newer declarative diagramming language that produces clean, readable output. Works well for service-level diagrams.
Choose based on where your team already works. If your docs live in Markdown files in a Git repo, Mermaid is frictionless. If you need precise UML notation and detailed class diagrams, PlantUML gives you more control. For a deeper comparison, see our tooling breakdown for software documentation.
How do you keep microservices diagrams accurate over time?
The lifespan of a diagram's usefulness depends entirely on how you maintain it. Some practical approaches:
- Generate diagrams from code annotations Tools like PlantUML can parse Java, C#, or TypeScript source files annotated with UML stereotypes and auto-generate diagrams. This is the most reliable way to keep diagrams in sync.
- Store diagram source files in the service repository A
docs/architecture.pumlfile alongside the code means it gets reviewed and updated during normal development. - Use CI to render and publish Add a build step that renders
.pumlor Mermaid files into SVG/PNG and publishes them to your documentation site. This way, the latest version is always available without manual export. - Set a review cadence Even automated diagrams benefit from a human review each quarter to check that the abstractions still make sense and that no service has drifted outside its intended boundary.
A quick checklist before you share your diagram
- Each microservice is clearly separated into its own package or namespace.
- Only domain-relevant classes are shown no infrastructure or framework boilerplate.
- Cross-service communication uses interfaces, DTOs, or event objects not direct class-to-class lines.
- Communication style is annotated (REST, messaging, gRPC) on every cross-service dependency.
- Shared databases are explicitly flagged or eliminated.
- IDs are used for cross-service references instead of direct object associations where possible.
- The diagram source is version-controlled alongside your code.
- Someone who didn't create the diagram can read it and understand the service boundaries in under five minutes.
Start by sketching the three services you're most actively developing. Use a simple PlantUML or Mermaid file, check it into your repo, and iterate from there. A small, accurate diagram that lives near the code beats a perfect one that nobody updates. If you need the markup syntax to get started, our UML class diagram code examples give you ready-to-use templates you can adapt to your own architecture.
How to Write Uml Diagram Markup in Plantuml
Uml Sequence Diagram Syntax Cheat Sheet and Markup Reference
Best Uml Diagram Markup Tools for Software Documentation
Uml Activity Diagram Markup Languages: Mermaid vs Plantuml vs Graphviz Comparison
Sequence Diagram Code Cheat Sheet: Quick Reference for All Syntax Essentials
Uml Diagram Code Syntax Explained