PlantUML Primer
Text-based diagramming for version-controlled architecture documentation

1. Purpose and Philosophy
PlantUML was created to solve a fundamental problem: visual diagrams in traditional tools (Visio, draw.io) don’t version control well and drift from code. By describing diagrams as text, PlantUML treats diagrams like code—diffable, mergeable, and automatically renderable.
Strengths:
- Version control friendly: Plain text files in Git show meaningful diffs
- Consistency: Automatic layout ensures uniform styling across diagrams
- Integration: Renders in CI/CD, documentation sites, IDEs, and wikis
- Expressiveness: Supports UML (class, sequence, component), C4 models, Gantt charts, mind maps, and more
- Toolchain independence: Render via CLI, web service, or IDE plugins
Limitations:
- Layout control: Automatic layout sometimes produces suboptimal arrangements
- Learning curve: Syntax is terse; advanced features require documentation lookups
- Rendering dependencies: Requires Java runtime and Graphviz for some diagram types
- Visual tweaking: Fine-grained positioning and styling is limited compared to WYSIWYG tools
Use PlantUML for:
- Architecture diagrams in documentation (C4 models, component diagrams)
- Sequence diagrams for interaction flows
- Class diagrams for domain modeling
- Deployment and infrastructure diagrams
- Any diagram that should evolve with code
Avoid PlantUML for:
- High-fidelity mockups or pixel-perfect layouts
- Diagrams requiring frequent visual iteration (use draw.io for drafts, then migrate to PlantUML)
- Presentations where manual layout control is critical
Authoritative References:
- PlantUML Official Site — Syntax reference, examples, online editor
- PlantUML Language Reference Guide — Comprehensive syntax documentation
- Real World PlantUML — Community-contributed examples
- C4-PlantUML — C4 model integration
2. Getting Started
To begin creating PlantUML diagrams, you need a text editor and a way to render the diagrams. The quickest path is using an online editor or IDE plugin.
Quickest start (no installation):
- Visit PlantUML Online Server
- Write your diagram syntax in the text area
- See the rendered diagram update in real-time
- Export to PNG or SVG when satisfied
Recommended local setup:
Option A: VS Code (cross-platform):
- Install VS Code
- Install the PlantUML extension
- Create a file with
.pumlextension - Press
Alt+Dto preview the diagram - The extension handles rendering automatically (uses online server by default)
Option B: Command-line with Java:
- Install Java Runtime (JRE 8 or later)
- macOS:
brew install openjdk - Ubuntu/Debian:
sudo apt-get install default-jre - Windows: Download from java.com
- macOS:
- Install PlantUML
- macOS:
brew install plantuml - Ubuntu/Debian:
sudo apt-get install plantuml - Windows: Download JAR from plantuml.com/download
- macOS:
- Install Graphviz (required for some diagram types)
- macOS:
brew install graphviz - Ubuntu/Debian:
sudo apt-get install graphviz - Windows: Download from graphviz.org
- macOS:
- Render a diagram:
plantuml diagram.puml
For IntelliJ IDEA users:
- Install the PlantUML Integration plugin
- Create
.pumlfiles and see live previews in the editor
Once set up, create a simple sequence diagram to verify everything works:
@startuml
Alice -> Bob: Hello
Bob --> Alice: Hi there!
@enduml
Save this as test.puml and render it to confirm your environment is ready.
3. Core Syntax
Minimal cheatsheet:
Sequence Diagram
@startuml
actor User
participant "Web UI" as UI
participant "API" as API
database "Database" as DB
User -> UI: Request page
UI -> API: GET /tasks
API -> DB: SELECT * FROM tasks
DB --> API: Task list
API --> UI: JSON response
UI --> User: Rendered page
@enduml
Component Diagram
@startuml
package "Presentation Layer" {
[Web UI]
[REST API]
}
package "Business Logic" {
[Task Service]
[Workflow Engine]
}
database "PostgreSQL" {
[Tasks Table]
}
[Web UI] --> [REST API]
[REST API] --> [Task Service]
[Task Service] --> [Workflow Engine]
[Task Service] --> [Tasks Table]
@enduml
Class Diagram
@startuml
class Task {
- id: UUID
- name: String
- status: Status
+ complete(): void
+ isPending(): boolean
}
enum Status {
PENDING
IN_PROGRESS
COMPLETED
}
Task --> Status
@enduml
Deployment Diagram
@startuml
node "Web Server" {
[Nginx]
}
node "Application Server" {
[Spring Boot App]
}
node "Database Server" {
database "PostgreSQL"
}
[Nginx] --> [Spring Boot App]: reverse proxy
[Spring Boot App] --> [PostgreSQL]: JDBC
@enduml
C4 Context Diagram
@startuml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml
Person(user, "User", "Task manager user")
System(taskSystem, "Task Management System", "Manages user tasks")
System_Ext(emailSystem, "Email System", "Sends notifications")
Rel(user, taskSystem, "Uses")
Rel(taskSystem, emailSystem, "Sends emails via")
@enduml
4. Patterns and Idioms
Documentation Structure
Organize diagrams alongside code or in dedicated directories:
project/
├── docs/
│ ├── architecture/
│ │ ├── context.puml # C4 context diagram
│ │ ├── containers.puml # C4 container diagram
│ │ └── components.puml # Component details
│ ├── sequences/
│ │ ├── user-login.puml
│ │ └── task-workflow.puml
│ └── domain/
│ └── task-model.puml # Class diagram
├── src/
└── README.md
Common Styling Patterns
@startuml
' Custom styling for consistent look
skinparam shadowing false
skinparam linetype ortho
skinparam rectangle {
BackgroundColor LightBlue
BorderColor DarkBlue
}
rectangle "Component A" as A
rectangle "Component B" as B
A --> B
@enduml
Including Shared Definitions
@startuml
' common-styles.iuml
!define COMPONENT_COLOR #LightBlue
!define DATABASE_COLOR #LightGreen
@enduml
@startuml
!include common-styles.iuml
rectangle "Service" COMPONENT_COLOR
database "DB" DATABASE_COLOR
@enduml
Embedding Notes and Documentation
@startuml
class Task {
+ complete()
}
note right of Task
Tasks transition from PENDING
to COMPLETED via complete()
method. Status changes are
immutable.
end note
5. Tooling and Rendering
PlantUML offers multiple rendering approaches, from command-line tools for batch processing to IDE integrations for interactive development. Choose the setup that best fits your workflow.
Command-Line Rendering
The command-line interface is ideal for automation, batch processing, and CI/CD pipelines.
# Install PlantUML (requires Java)
# macOS:
brew install plantuml
# Ubuntu/Debian:
sudo apt-get install plantuml
# Windows:
# Download from https://plantuml.com/download
# Render diagram to PNG
plantuml diagram.puml
# Render to SVG (vector, preferred for web)
plantuml -tsvg diagram.puml
# Render all .puml files in directory
plantuml src/diagrams/*.puml
# Watch for changes and auto-render
plantuml -gui src/diagrams/
IDE Integration
IDE plugins provide live previews, making it easy to iterate on diagrams while writing code or documentation.
- VS Code: PlantUML Extension
- Live preview, syntax highlighting, export
- IntelliJ IDEA: PlantUML Integration Plugin
- Eclipse: PlantUML Plugin
- Atom: PlantUML Viewer
Online Editors
For quick experimentation without installing anything, online editors render diagrams in your browser.
Rendering Services
You can embed diagrams dynamically in documentation by referencing source files through PlantUML’s public rendering service.
Embed in Markdown (GitHub, GitLab):

Build Integration
Automate diagram rendering in continuous integration pipelines to keep visuals in sync with code changes.
# GitHub Actions: Render PlantUML in CI
name: Render Diagrams
on: [push]
jobs:
render:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Render PlantUML
uses: grassedge/generate-plantuml-action@v1.5
with:
path: docs/diagrams
message: "Auto-generated diagrams"
6. Integration
PlantUML integrates naturally into documentation workflows, version control systems, and static site generators, treating diagrams as code artifacts.
Hugo/Jekyll Static Sites
# Pre-render diagrams in build pipeline
#!/bin/bash
for file in src/images/*.puml; do
plantuml -tsvg "$file" -o ../../static/images/
done
# Reference in markdown

Documentation as Code
Keep diagrams next to code they document:
project/
├── src/
│ ├── domain/
│ │ ├── task.py
│ │ └── task-model.puml # Domain model diagram
│ └── api/
│ ├── routes.py
│ └── api-sequence.puml # API interaction diagram
Version Control Workflow
# Edit diagram
vim docs/architecture.puml
# Render locally to verify
plantuml -tsvg docs/architecture.puml
# Commit both source and rendered (or generate in CI)
git add docs/architecture.puml static/images/architecture.svg
git commit -m "Update architecture diagram"
Automated Diagram Updates
# Makefile for diagram rendering
DIAGRAMS := $(wildcard docs/**/*.puml)
SVGS := $(DIAGRAMS:.puml=.svg)
all: $(SVGS)
%.svg: %.puml
plantuml -tsvg $<
clean:
rm -f $(SVGS)
.PHONY: all clean
7. Accessibility and Review
Accessibility Practices
- Alt text in markdown: Provide meaningful descriptions when embedding diagrams
 - SVG output preferred: Vector graphics scale without quality loss
- High contrast: Use
skinparam monochrome truefor black-and-white rendering - Descriptive labels: Avoid abbreviations; spell out component names
Review and Versioning
- Text diffs are readable: Reviewers can see diagram changes in Git diffs
- Comments in diagrams: Use
' single quotefor inline comments@startuml ' This diagram shows the authentication flow ' Updated 2024-01-15 to reflect OAuth integration actor User participant "Auth Service" as Auth User -> Auth: Login request @enduml - Version markers in diagrams:
@startuml title User Authentication Flow\n(Version 2.0 - OAuth Integrated) ... @enduml
Common Pitfalls
- Graphviz dependency: Some diagrams require Graphviz; install with PlantUML
- Large diagrams become unreadable: Break into multiple smaller diagrams
- Layout quirks: Use
skinparam linetype orthofor cleaner orthogonal lines - Color accessibility: Avoid red-green combinations; test with colorblind simulators
- Over-detailing: Keep diagrams high-level; excessive detail obscures intent
8. Example and Reference
Complete working example: Three-Layer Architecture
@startuml
' File: architecture-layers.puml
' Three-Layer Architecture diagram for task management system
skinparam shadowing false
skinparam linetype ortho
skinparam componentStyle rectangle
title Three-Layer Architecture\nTask Management System
package "Presentation Layer" as PL {
component "Web UI" as WebUI
component "REST API" as API
}
package "Business Logic Layer" as BLL {
component "Task Service" as TaskSvc
component "User Service" as UserSvc
component "Notification Service" as NotifSvc
}
package "Data Access Layer" as DAL {
component "Task Repository" as TaskRepo
component "User Repository" as UserRepo
database "PostgreSQL" as DB
}
' Dependencies
WebUI --> API
API --> TaskSvc
API --> UserSvc
TaskSvc --> NotifSvc
TaskSvc --> TaskRepo
UserSvc --> UserRepo
TaskRepo --> DB
UserRepo --> DB
' Notes
note right of PL
Handles HTTP requests,
input validation,
session management
end note
note right of BLL
Domain logic,
business rules,
workflow orchestration
end note
note right of DAL
Persistence operations,
query optimization,
transaction management
end note
@enduml
Render:
plantuml -tsvg architecture-layers.puml
Embed in documentation:
# System Architecture
Our system uses a three-layer architecture to separate concerns:

Each layer has clear responsibilities and dependencies flow downward only.
Applying custom styling to the example: