smhk

Some useful PlantUML architecture diagrams

PlantUML is very useful for creating architecture diagrams using text. However, the official documentation is so big (a 606 page PDF as of v1.2025.0) that it’s not always easy to find what I’m looking for. Yet, despite being so big, not everything is documented. For example, there are 45 “TODO"s, and norank is not mentioned anywhere (but is mentioned in the unofficial but extremely helpful The Hitchhiker’s Guide to PlantUML).

So, following is a small collection of useful example architecture diagrams:

Example Diagrams §

Layered Architecture §

While the following diagram looks fairly simple, a lot of wrangling is required under the hood to ensure the layers and components are aligned correctly:

5G layers
Simple stack diagram

The main things to be aware of are:

  1. For structural purposes, a hidden right arrow is used between each component in a layer to ensure they are horizontally aligned in the correct order.
  2. For structural purposes, a hidden down arrow is used between the first component from each layer to ensure that the layers are left-aligned.
  3. Visible arrows:
    • Use norank to prevent them from taking prescedence over the hidden connections used for structural purposes and breaking the layout.
    • Except, if a visible arrow connects two components that were connected for structural purposes, the hidden arrow is omitted and norank is omitted. This prevents multiple arrows from connecting two components and breaking the layout.
@startuml
package LAYER_3 {
  component Comp30 {
  }
  component Comp31 {
  }
  component Comp32 {
  }
  component Comp33 {
  }
}

package LAYER_2 {
  component Comp20 {
  }
  component Comp21 {
  }
  component Comp22 {
  }
  component Comp23 {
  }
  component Comp24 {
  }
  component Comp25 {
  }
  component Comp26 {
  }
  component Comp27 {
  }
}

package LAYER_1 {
  component Comp10 {
  }
  component Comp11 {
  }
  component Comp12 {
  }
  component Comp13 {
  }
  component Comp14 {
  }
  component Comp15 {
  }
  component Comp16 {
  }
  component Comp17 {
  }
}

' Hidden connections
' ------------------

' Use hidden right connections to encourage the components
' within each layer to be placed in the desired order.
Comp30 -[hidden]r- Comp31
Comp31 -[hidden]r- Comp32
Comp32 -[hidden]r- Comp33
Comp20 -[hidden]r- Comp21
Comp21 -[hidden]r- Comp22
Comp22 -[hidden]r- Comp23
Comp23 -[hidden]r- Comp24
Comp24 -[hidden]r- Comp25
Comp25 -[hidden]r- Comp26
Comp26 -[hidden]r- Comp27
Comp10 -[hidden]r- Comp11
Comp11 -[hidden]r- Comp12
Comp12 -[hidden]r- Comp13
Comp13 -[hidden]r- Comp14
Comp14 -[hidden]r- Comp15
Comp15 -[hidden]r- Comp16
Comp16 -[hidden]r- Comp17

' Use hidden down connections between the first component in each
' layer to encourage all the layers to be left-aligned.
' NOTE: Use longer arrows to force more space between the layers, so
' that the visible arrows can be more clearly distinguished.
' NOTE: Since we later create a *visible* connection from Comp20 to
' Comp10, we omit create a hidden connection here, otherwise the
' visible connection ends up curving to avoid the hidden one.
Comp30 -[hidden]d-- Comp20
'Comp20 -[hidden]d-- Comp10

' Visible connections
' -------------------

' NOTE: Use norank to prevent these visible connections from taking
' prescedence over the hidden connections and breaking the layout,
' *except* for the visible connections which are equivalent to the
' hidden connections that we have omitted.
Comp23 -[norank,#6666ff,dotted]-> Comp10
Comp21 -[norank,dotted,#red]-> Comp10
Comp20 -d--> Comp10
Comp20 -[norank]-> Comp16
@enduml

For reference see this answer.

Block Architecture §

The Hitchhiker’s Guide to PlantUML provides some useful individual examples of C4 diagrams and of network diagrams with icons, but it does not combine the two. Following is an example of how you can combine them to get icons in your C4 diagrams:

PlantUML RAN Architecture
PlantUML RAN Architecture

In short, you include both C4 and osaPuml. Then you can use the objects from C4 such as Container, and the images from osaPuml such as <$osa_wireless_network>:

@startuml
set separator none
title Example RAN Architecture

left to right direction

!include <C4/C4>
!include <C4/C4_Context>
!include <C4/C4_Container>

!define osaPuml https://raw.githubusercontent.com/Crashedmind/PlantUML-opensecurityarchitecture2-icons/master
!include osaPuml/Common.puml
!include osaPuml/User/all.puml
!include osaPuml/Hardware/all.puml
!include osaPuml/Misc/all.puml
!include osaPuml/Server/all.puml
!include osaPuml/Site/all.puml

Person(User, "User")

Container(UE, "<$osa_iPhone>\nUE")

System_Boundary(CellTower, "Cell Tower") {
  Container(RU, "<$osa_wireless_network>\nRU")
  Container(DU, "<$osa_hub>\nDU\n")
}

Container(CU, "<$osa_hub>\nCU")
Container(Core, "<$osa_server>\nCore")
Container(Internet, "<$osa_cloud>\nInternet")

BiRel(User, UE, "")
BiRel(UE, RU, "RF", "Band n78")
BiRel(RU, DU, "eCPRI")
BiRel(DU, CU, "IP")
BiRel(CU, Core, "IP")
BiRel(Core, Internet, "IP")
@enduml

Software Layers §

Using package, interface, class, <<Node>> and some styling can be a useful way to represent software files:

5G Layers
5G Layers

The arrow directions are necessary to ensure the layout flows correctly. The <<(X,Y)>> syntax after each interface or class allows specifying the text and colour for the small icon:

@startuml

' L3

package source.L3.L3_rrc <<Node>> {
  interface L3_rrc_h as "L3_rrc.h" <<(H,orchid)>>
  class L3_rrc_c as "L3_rrc.c" <<(C,yellow)>>
}

' L2

package source.L2.L2_pdcp <<Node>> {
  interface L2_pdcp_h as "L2_pdcp.h" <<(H,orchid)>>
  class L2_pdcp_c as "L2_pdcp.c" <<(C,yellow)>>
}

package source.L2.L2_rlc <<Node>> {
  interface L2_rlc_h as "L2_rlc.h" <<(H,orchid)>>
  class L2_rlc_c as "L2_rlc.c" <<(C,yellow)>>
}

package source.L2.L2_mac <<Node>> {
  interface L2_mac_h as "L2_mac.h" <<(H,orchid)>>
  class L2_mac_c as "L2_mac.c" <<(C,yellow)>>
}

' L1

package source.L1.L1_high <<Node>> {
  interface L1_high_h as "L1_high.h" <<(H,orchid)>>
  class L1_high_c as "L1_high.c" <<(C,yellow)>>
}

package source.L1.L1_low <<Node>> {
  interface L1_low_h as "L1_low.h" <<(H,orchid)>>
  class L1_low_c as "L1_low.c" <<(C,yellow)>>
}

' L3

L3_rrc_c -up[bold]-> L3_rrc_h
L3_rrc_c -up[bold]-> L2_pdcp_h

' L2

L2_pdcp_c -up[bold]-> L2_pdcp_h
L2_pdcp_c -up[bold]-> L2_rlc_h

L2_rlc_c -up[bold]-> L2_rlc_h
L2_rlc_c -up[bold]-> L2_mac_h

L2_mac_c -up[bold]-> L2_mac_h
L2_mac_c -up[bold]-> L1_high_h

' L1

L1_high_c -up[bold]-> L1_high_h
L1_high_c -up[bold]-> L1_low_h

L1_low_c -up[bold]-> L1_low_h

@enduml

Simple Stack §

Creole is the markup language used by PlantUML. As well as basic markup (e.g. bold, italic, font colour), it can do dividers, headings and icons.

Using dividers we can split up a node to create a very simple stack diagram. See 22.6 “Horizontal Lines” for more types of dividers and titles, e.g. ..My title...

5G layers
Simple stack diagram

This is quite limited. It is not possible to change the background colour of each section, but you can change the text colour:

@startuml

' Force the diagram to be wider
scale 400 width

' Specify colour for background and headings
node Node #dfd [
  <b><color #262>L3</color></b>
  * RRC
  ---
  <b><color #262>L2</color></b>
  * PDCP
  * RLC
  * MAC
  ===
  <i>FAPI <<interface>></i>
  ===
  <b><color #262>L1</color></b>
  * PHY
]
@enduml