If you've ever needed to explain how a system works to another developer, a PlantUML sequence diagram is one of the fastest ways to do it. Instead of drawing boxes and arrows by hand, you write a few lines of text and get a clear, professional-looking diagram. The code examples below show you exactly how to build these diagrams from scratch, whether you're mapping a simple login flow or a complex microservices interaction.
What Exactly Is a PlantUML Sequence Diagram?
A PlantUML sequence diagram is a text-based diagram that shows how different participants (objects, users, services) communicate over time. You write simple, readable code, and PlantUML renders it into an image. The diagram reads left to right and top to bottom, showing messages flowing between participants in the order they happen.
PlantUML is an open-source tool that takes plain text descriptions and turns them into UML diagrams. Sequence diagrams are one of the most popular diagram types because they make it easy to visualize workflows, API calls, authentication flows, and system interactions. You can learn more about the full syntax details in our UML sequence diagram syntax reference.
How Do You Write a Basic PlantUML Sequence Diagram?
Every PlantUML sequence diagram starts with @startuml and ends with @enduml. Between those tags, you define participants and the messages they send to each other. Here's the simplest possible example:
@startuml
Alice -> Bob: Hello Bob
Bob --> Alice: Hi Alice
@enduml
This creates two participants, Alice and Bob, with a solid arrow from Alice to Bob and a dashed return arrow back. The -> operator draws a solid arrow, while --> draws a dashed one (typically used for responses).
You can also declare participants explicitly to control their order and give them aliases:
@startuml
actor User
participant "API Gateway" as GW
participant "Auth Service" as Auth
database "User DB" as DB
User -> GW: POST /login
GW -> Auth: validateCredentials()
Auth -> DB: SELECT user WHERE email=?
DB --> Auth: user record
Auth --> GW: JWT token
GW --> User: 200 OK + token
@enduml
This example uses four different participant types: actor (stick figure), participant (rectangle), and database (cylinder). Choosing the right shape helps readers quickly identify what kind of participant they're looking at.
What Are Some Common PlantUML Sequence Diagram Code Examples?
Simple Request-Response Between Two Services
@startuml
participant Client
participant Server
Client -> Server: HTTP GET /users
Server --> Client: 200 OK (JSON)
@enduml
This is the most basic interaction pattern. It's useful when documenting API endpoints or explaining a single service call. Keep it this simple when you only need to show one request and one response.
Adding Notes and Activation Bars
@startuml
participant "Web App" as App
participant "Payment Service" as Pay
participant "Stripe API" as Stripe
App -> Pay: processPayment(orderId)
activate Pay
Pay -> Stripe: POST /v1/charges
activate Stripe
Stripe --> Pay: charge.id
deactivate Stripe
note right of Pay: Store charge ID in order record
Pay --> App: success(orderId)
deactivate Pay
@enduml
The activate/deactivate keywords draw vertical bars showing when a participant is actively processing. Notes attach extra context directly to a participant. These two features make diagrams much easier to read.
Conditional Logic with alt and opt Blocks
@startuml
participant User
participant "Auth Service" as Auth
User -> Auth: login(email, password)
alt credentials are valid
Auth --> User: 200 OK (token)
else credentials are invalid
Auth --> User: 401 Unauthorized
end
@enduml
The alt block shows branching logic. If you only have one optional path (no "else" case), use opt instead. For multiple conditions, you can chain them with else if inside the alt block.
Loops and Parallel Execution
@startuml
participant Scheduler
participant "Worker A" as WA
participant "Worker B" as WB
Scheduler -> WA: startBatch()
Scheduler -> WB: startBatch()
par parallel processing
WA -> WA: process(items[0..499])
WB -> WB: process(items[500..999])
end
WA --> Scheduler: done
WB --> Scheduler: done
@enduml
The par block shows concurrent operations. Use loop to represent repeated actions, like retrying a request: loop 3 retries.
Grouping Messages with Boxes and Dividers
@startuml
box "Frontend" #LightBlue
participant Browser
end box
box "Backend" #LightGreen
participant API
participant Cache
end box
Browser -> API: GET /products
API -> Cache: get("products")
Cache --> API: null (cache miss)
API -> API: queryDatabase()
API --> Browser: product list
== Cache Refresh ==
API -> Cache: set("products", data, TTL=300)
@enduml
Boxes visually group related participants. The double-equals syntax (==) creates a horizontal divider to separate phases of an interaction.
How Do You Handle Self-Calls and Nested Messages?
When a participant calls itself (like an internal method invocation), you send a message to the same participant name:
@startuml
participant Controller
Controller -> Controller: validate(request)
@enduml
For nested calls, activate the participant again to create stacked activation bars:
@startuml
participant OrderService
participant InventoryService
OrderService -> InventoryService: checkStock(productId)
activate InventoryService
InventoryService -> InventoryService: findProduct(productId)
activate InventoryService
InventoryService --> InventoryService: product
deactivate InventoryService
InventoryService --> OrderService: stockLevel
deactivate InventoryService
@enduml
This shows two levels of activation, making it clear that findProduct runs inside checkStock.
What Are the Most Common Mistakes When Writing PlantUML Sequence Diagrams?
Forgetting @startuml or @enduml. PlantUML won't render without these bookend tags. Double-check that both are present before debugging anything else.
Mixing up arrow types. A solid arrow (->) means a synchronous call or a message. A dashed arrow (-->) usually represents a response. Using the wrong one confuses readers about what's a request vs. a reply.
Using participant names with spaces without aliases. If a participant name has a space, wrap it in quotes and give it an alias. Writing API Gateway -> Auth Service: verify() without quotes or aliases will cause rendering errors. The correct way is: participant "API Gateway" as GW.
Overloading a single diagram. Trying to show an entire system in one sequence diagram makes it unreadable. Break it into multiple smaller diagrams, each covering one specific flow. For comparing how different scripting languages handle sequence diagrams, see our scripting language comparison for sequence diagrams.
Skipping activation blocks. Without activate/deactivate, readers can't tell when a participant is actively doing something. Even simple diagrams become clearer with these markers.
How Can You Render and Share PlantUML Sequence Diagrams?
You have several options for turning your PlantUML code into images:
- Online editors The official PlantUML server lets you paste code and get a diagram instantly. You can also try our online sequence diagram generator for a quick workflow.
- IDE plugins VS Code, IntelliJ, and other editors have PlantUML plugins that show live previews as you type.
- Command line Download the PlantUML JAR file and generate PNG, SVG, or PDF output from the terminal.
- CI/CD integration Add PlantUML generation to your build pipeline so diagrams always stay in sync with your code.
What Tips Help You Write Better PlantUML Sequence Diagrams?
- Use aliases for long names. Instead of typing "PaymentProcessingService" every time, define participant "PaymentProcessingService" as PPS and use PPS throughout.
- Keep participants under 7 per diagram. More than that and the diagram becomes hard to scan. Split into linked diagrams instead.
- Use colors to distinguish systems. Add color with syntax like participant API #LightBlue or wrap participants in colored boxes.
- Add a title. Start your diagram with title User Login Flow v2 so anyone viewing the image knows what it covers.
- Version your diagrams. Store the .puml source files in your repo alongside your code. Diagrams that live outside version control will drift out of date.
- Use footnotes for assumptions. footnote right of User: Assumes MFA is disabled adds context without cluttering the message flow.
Practical Checklist for Your Next PlantUML Sequence Diagram
- Identify the specific flow you want to document (one flow per diagram).
- List all participants and choose the right shapes (actor, participant, database, collections, control, entity).
- Write the message exchanges in chronological order from top to bottom.
- Add activate/deactivate blocks to show processing time for each participant.
- Include alt, opt, loop, or par blocks for branching, optional, repeated, or concurrent logic.
- Use notes and colors to add context without overcrowding.
- Add a title and version number at the top of the diagram.
- Render the diagram and check that it reads clearly at the size it will be displayed.
- Commit the .puml source file to version control.
- Share the diagram link or exported image with your team.
Start by picking one active feature or bug ticket you're working on right now, and write a sequence diagram for the main interaction. It takes about five minutes, and you'll immediately see whether the flow makes sense or has gaps worth fixing.
Comparing Sequence Diagram Scripting Languages: Features and Syntax Guide
Mermaid.js Sequence Diagram Code Snippets and Examples
Online Sequence Diagram Script Generator
Uml Sequence Diagram Syntax Guide
How to Write Flowchart Code From Scratch: a Complete Beginner's Tutorial
Mermaid Flowchart Syntax Examples for Github Repositories