PlantUML preprocessor directives & icon libraries

puml.online

When 10 PlantUML diagrams share the same skin and palette, preprocessor directives let you extract common code. When you want intuitive icons for docs, the icon libraries do that — together they take PlantUML from “draw each one” to “template-driven.”

Preprocessor cheat sheet

Directive Use
!include <path> Inline an external PlantUML file / text
!includeurl <url> Inline from URL
!include_once Include only the first time
!define <VAR> <value> Define a preprocessor variable
!function <name>(args) Define a preprocessor function
%variable_name Reference a preprocessor variable
%date("format") Current date
%dirpath(...) / %filename(...) Filename helpers
!if / !else / !endif Preprocessor conditions
!definelong Multi-line definition
%load_json / %load_yaml Read external data

1. !include (most common)

Extract shared styles:

1
2
3
4
5
6
# source/plantuml/_theme.puml
!define THEME_DARK
skinparam backgroundColor #FAFAFA
skinparam BorderColor #2F4858
skinparam ArrowColor #2F4858
skinparam FontColor #1F2328

Main file:

1
2
3
4
5
6
7
8
@startuml
!include /path/to/_theme.puml

class Order
class Product
Order --> Product

@enduml

!include inlines content at preprocessing time.

Internal-network note: enterprise networks often block GitHub raw; vendor locally.

C4 inclusion

1
2
3
4
5
6
7
8
9
10
@startuml
!include ../plantuml/c4/C4_Container.puml

Person(user, "User")
Container(web, "Web", "React")
Container(api, "API", "Go")

Rel(user, web)
Rel(web, api)
@enduml

Path separators

1
2
!include ../shared/styles.puml
!include ../../c4/C4_Container.puml

2. !define / %variable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@startuml
!define COLOR_PRIMARY #A31F34
!define COLOR_SUCCESS #20A464
!define COLOR_WARNING #F4B40A

skinparam class {
BackgroundColor %COLOR_PRIMARY
FontColor white
}

class A
class B
A -> B

@enduml

!define declares; %NAME references.

Multi-line !definelong

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@startuml
!definelong STYLE_CLASS_PRIMARY
skinparam class {
BackgroundColor #A31F34
FontColor white
BorderColor white
}
!enddefinelong

STYLE_CLASS_PRIMARY

class A
class B

@enduml

3. !function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@startuml
!function $accent($type)
!if ($type == "primary")
!return #A31F34
!else
!return #6B7280
!endif
!endfunction

class A
A -> B : %accent("primary")
A -> C : %accent("warning")

@enduml

Real: status colors

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@startuml
!function $status_color($s)
!if ($s == "ok")
!return #20A464
!elseif ($s == "warn")
!return #F4B40A
!elseif ($s == "fail")
!return #DC2626
!else
!return #6B7280
!endif
!endfunction

skinparam class {
BackgroundColor $status_color("ok")
}

class Healthy
@enduml

4. %date / %time

1
2
3
@startuml
title Report generated at %date("yyyy-MM-dd HH:mm")
@enduml

Java SimpleDateFormat patterns:

Pattern Output
yyyy-MM-dd 2026-07-29
yyyy 2026
MM/dd/yy 07/29/26
dd MMM yyyy 29 Jul 2026

Title with date

1
2
3
4
5
6
7
8
@startuml
title System status - %date("yyyy-MM-dd")

class Service1
class Service2
class Service3

@enduml

5. !if / !endif

1
2
3
4
5
6
7
8
9
10
11
12
13
@startuml
!define DEBUG true

!if (DEBUG == true)
skinparam class {
BackgroundColor #F4B40A
BorderColor #DC2626
}
!endif

class Order

@enduml

Multi-branch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@startuml
!define THEME "dark"

!if (THEME == "dark")
skinparam BackgroundColor #161B22
skinparam FontColor #E6EDF3
!elseif (THEME == "light")
skinparam BackgroundColor #FAFAFA
skinparam FontColor #1F2328
!else
skinparam BackgroundColor white
skinparam FontColor black
!endif

class Order
@enduml

Switch theme via CLI

1
2
plantuml -DTHEME=dark *.puml
plantuml -DTHEME=light *.puml

6. %load_json / %load_yaml

1
2
3
@startjson
%load_json("data.json")
@endjson

External data becomes input:

1
2
3
4
5
cat <<EOF | java -jar plantuml.jar -pipe >out.svg
@startjson
%load_json("$1")
@endjson
EOF
1
./render.sh config.json

Icon libraries

PlantUML supports standard open-source icon libraries for richer diagrams.

OpenIconic

1
2
3
4
5
6
@startuml

class Application <<&person>>
database Database <<&cylinder>>

@enduml

<<&name>> references OpenIconic. Common:

Code Icon
<&person> user
<&cog> gear / settings
<&lock-locked> lock
<&check> check
<&x> cross
<&bell> bell
<&calendar> calendar
<&graph> chart
<&database> database
<&cloud> cloud
<&bolt> bolt

Built-in stereotypes

1
2
3
4
5
6
7
8
9
10
@startuml

class Server <<&server>>
class Database <<&database>>
class Queue <<&queue>>
class Network <<&network>>
class Storage <<&storage>>
class User <<&user>>

@enduml

FontAwesome / Material / AWS

1
2
3
4
5
6
7
8
9
10
11
12
@startuml

!include <material/common>
!include <material/server>
!include <material/database>

node "API Gateway" as gw <<$material/server>>
database "Postgres" as db <<$material/database>>

gw --> db

@enduml

Material Icon library

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@startuml
!include <material/common>
!include <material/server>
!include <material/database>
!include <material/globe_network>
!include <material/api>

class User <<$material/account>>
class API <<$material/api>>
class Server <<$material/server>>

User --> API
API --> Server

@enduml

AWS / Azure / GCP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@startuml
!include <aws/common>
!include <aws/Compute/EC2>
!include <aws/Database/RDS>
!include <aws/Networking/ELB>

class WebServer <<$aws_compute_ec2>>
class DB <<$aws_database_rds>>
class LoadBalancer <<$aws_networking_elb>>

WebServer --> DB
LoadBalancer --> WebServer

@enduml

Real: full cloud architecture

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@startuml
!include <aws/common>
!include <aws/Compute/EC2>
!include <aws/Database/RDS>
!include <aws/Networking/ELB>
!include <aws/Storage/S3>
!include <aws/Security/Cognito>

actor User <<$material/account>>

cloud "VPC" {
LoadBalancer <<$aws_networking_elb>>

EC2 <<$aws_compute_ec2>>

RDS <<$aws_database_rds>>
}

S3 <<$aws_storage_s3>>
Cognito <<$aws_security_cognito>>

User --> Cognito : auth
User --> LoadBalancer : HTTPS
LoadBalancer --> EC2 : HTTP
EC2 --> RDS : SQL
EC2 --> S3 : Static assets

@enduml

Custom stereotypes

1
2
3
4
5
6
7
8
@startuml
skinparam stereotypeCBackgroundColor #FAFAFA

class OrderService <<(Q, #A31F34) Service>>
class PaymentService <<(P, #20A464) Service>>
class UserController <<(C, #F4B40A) Controller>>

@enduml

<<(X, #color) Label>> defines custom color + label.

Real-world: template-driven diagrams

1
2
3
4
5
6
7
8
9
# _include/puml/style.puml
!define COLOR_PRIMARY #A31F34
!define COLOR_BG #FAFAFA

skinparam {
BackgroundColor %COLOR_BG
BorderColor %COLOR_PRIMARY
ArrowColor %COLOR_PRIMARY
}
1
2
# _include/puml/icons.puml
!include <material/common>
1
2
3
4
5
6
7
8
9
10
@startuml
!include _include/puml/style.puml
!include _include/puml/icons.puml

class OrderService <<$material/server>>
class PaymentService <<$material/server>>

OrderService --> PaymentService

@enduml

CI render:

1
2
3
4
- name: Render diagrams
run: |
# !include relative paths: cd to source/
find source -name '*.puml' | xargs -I {} java -jar plantuml.jar -tpng {}

Anti-patterns

1. Complex preprocessor functions

1
2
3
4
5
6
7
8
9
!function $calc($a, $b)
!if ($a > 100 && $b > 50)
!return $a * $b + 100
!elseif ($a < 0)
!return 0
!else
!return $a + $b
!endif
!endfunction

When logic gets long it’s hard to debug. Keep functions tiny — color picks, text replacements — and use !define for everything else.

2. !includeurl from GitHub

1
!includeurl https://raw.githubusercontent.com/.../C4_Container.puml

CI often fails on flaky network. Vendor locally.

3. Icon overload

1
2
3
4
5
6
7
8
9
10
11
class A
class B
class C
class D
class E
<<$material/server>>
<<$material/database>>
<<$material/api>>
<<$material/globe_network>>
<<$material/storage>>
@enduml

When icon library runs out of variety, icons repeat. Worse than no icons.

Review checklist

Preprocessor

  • Shared styles extracted to a file?
  • Variables have semantic names? COLOR_PRIMARY not A1?
  • !include uses local paths; no external URLs?
  • Conditional branches cover only what you actually need?

Icons

  • Icons match the business concept of each class?
  • Single icon library per diagram — no mixing?
  • Style consistent?

TL;DR

Preprocessor + icon libraries lift PlantUML from “draw each one” to “template-driven.” Extract common styles + pick an icon library + write a render script, and your entire doc deck renders in one pass.

  • Title: PlantUML preprocessor directives & icon libraries
  • Author: puml.online
  • Created at : 2026-07-29 16:05:00
  • Updated at : 2026-08-14 21:34:29
  • Link: https://puml.online/blog/plantuml-preprocessing-icons-en/
  • License: This work is licensed under CC BY-NC-SA 4.0.