Skip to content

Instantly share code, notes, and snippets.

@nmandzyk
Last active April 22, 2026 10:13
Show Gist options
  • Select an option

  • Save nmandzyk/c14ad6b0701903996d895660056a66ee to your computer and use it in GitHub Desktop.

Select an option

Save nmandzyk/c14ad6b0701903996d895660056a66ee to your computer and use it in GitHub Desktop.
PlantUML macros
' ============================================================================
' C4-MACROS.PUML — Self-Contained C4 Model Macro Library for Confluence
' ============================================================================
'
' A complete, self-contained PlantUML macro library implementing the C4 model
' (https://c4model.com) by Simon Brown. Designed for Confluence PlantUML
' plugins where external !include URLs may not be available.
'
' USAGE:
' Option A — Copy-paste this entire block at the top of your diagram
' (between @startuml and your diagram content).
' Option B — Store as a Confluence page attachment and reference with:
' !include <attachment-url>/c4-macros.puml
'
' SUPPORTED DIAGRAM TYPES:
' Level 1 — System Context (Person, System, System_Ext)
' Level 2 — Container (Container, ContainerDb, ContainerQueue)
' Level 3 — Component (Component, Component_Ext)
' Level 4 — Deployment (Node, Container inside nodes)
'
' ============================================================================
' ----------------------------------------------------------------------------
' COLOR PALETTE (Standard C4 Model Colors)
' ----------------------------------------------------------------------------
!$PERSON_BG = "#08427B"
!$PERSON_BORDER = "#073B6F"
!$SYSTEM_BG = "#1168BD"
!$SYSTEM_BORDER = "#0B4884"
!$EXTERNAL_BG = "#999999"
!$EXTERNAL_BORDER = "#8A8A8A"
!$CONTAINER_BG = "#438DD5"
!$CONTAINER_BORDER = "#3C7FC0"
!$COMPONENT_BG = "#85BBF0"
!$COMPONENT_BORDER = "#78A8D8"
!$BOUNDARY_BG = "#FFFFFF"
!$BOUNDARY_BORDER = "#444444"
!$FONT_WHITE = "#FFFFFF"
!$FONT_DARK = "#000000"
!$REL_COLOR = "#707070"
!$REL_LINE_COLOR = "#707070"
' ----------------------------------------------------------------------------
' GLOBAL SKIN PARAMETERS
' ----------------------------------------------------------------------------
skinparam defaultTextAlignment center
skinparam wrapWidth 200
skinparam maxMessageSize 150
skinparam shadowing false
skinparam roundCorner 5
' Arrow styling
skinparam ArrowColor $REL_LINE_COLOR
skinparam ArrowFontColor $REL_COLOR
skinparam ArrowFontSize 11
' Hide stereotype labels (<<system>>, <<container>>, etc.)
hide stereotype
' Stereotype-based styling for boundaries
skinparam rectangle<<boundary>> {
BorderStyle dashed
BackgroundColor $BOUNDARY_BG
BorderColor $BOUNDARY_BORDER
FontColor $BOUNDARY_BORDER
RoundCorner 0
FontSize 14
FontStyle bold
StereotypeFontSize 0
}
' Node styling for deployment diagrams
skinparam node {
BackgroundColor #FFFFFF
BorderColor #444444
FontColor #444444
}
' ============================================================================
' PERSON MACROS
' ============================================================================
' Persons represent users (human or system actors) interacting with the system.
!unquoted procedure Person($alias, $label, $descr="")
!if ($descr != "")
actor "==$label\n\n<size:11><i>$descr</i></size>" <<person>> as $alias $PERSON_BG
!else
actor "==$label" <<person>> as $alias $PERSON_BG
!endif
!endprocedure
!unquoted procedure Person_Ext($alias, $label, $descr="")
!if ($descr != "")
actor "==$label\n\n<size:11><i>$descr</i></size>" <<person_ext>> as $alias $EXTERNAL_BG
!else
actor "==$label" <<person_ext>> as $alias $EXTERNAL_BG
!endif
!endprocedure
' ============================================================================
' SYSTEM MACROS (Level 1 — Context Diagrams)
' ============================================================================
' Systems are the highest level of abstraction — entire software systems.
!unquoted procedure System($alias, $label, $descr="")
!if ($descr != "")
rectangle "==$label\n<size:11>[Software System]</size>\n\n<size:11>$descr</size>" <<system>> as $alias $SYSTEM_BG
!else
rectangle "==$label\n<size:11>[Software System]</size>" <<system>> as $alias $SYSTEM_BG
!endif
!endprocedure
!unquoted procedure System_Ext($alias, $label, $descr="")
!if ($descr != "")
rectangle "==$label\n<size:11>[Software System]</size>\n\n<size:11>$descr</size>" <<system_ext>> as $alias $EXTERNAL_BG
!else
rectangle "==$label\n<size:11>[Software System]</size>" <<system_ext>> as $alias $EXTERNAL_BG
!endif
!endprocedure
!unquoted procedure SystemDb($alias, $label, $descr="")
!if ($descr != "")
database "==$label\n<size:11>[Database]</size>\n\n<size:11>$descr</size>" <<system_db>> as $alias $SYSTEM_BG
!else
database "==$label\n<size:11>[Database]</size>" <<system_db>> as $alias $SYSTEM_BG
!endif
!endprocedure
!unquoted procedure SystemDb_Ext($alias, $label, $descr="")
!if ($descr != "")
database "==$label\n<size:11>[Database]</size>\n\n<size:11>$descr</size>" <<system_db_ext>> as $alias $EXTERNAL_BG
!else
database "==$label\n<size:11>[Database]</size>" <<system_db_ext>> as $alias $EXTERNAL_BG
!endif
!endprocedure
!unquoted procedure SystemQueue($alias, $label, $descr="")
!if ($descr != "")
queue "==$label\n<size:11>[Queue]</size>\n\n<size:11>$descr</size>" <<system_queue>> as $alias $SYSTEM_BG
!else
queue "==$label\n<size:11>[Queue]</size>" <<system_queue>> as $alias $SYSTEM_BG
!endif
!endprocedure
!unquoted procedure SystemQueue_Ext($alias, $label, $descr="")
!if ($descr != "")
queue "==$label\n<size:11>[Queue]</size>\n\n<size:11>$descr</size>" <<system_queue_ext>> as $alias $EXTERNAL_BG
!else
queue "==$label\n<size:11>[Queue]</size>" <<system_queue_ext>> as $alias $EXTERNAL_BG
!endif
!endprocedure
' ============================================================================
' CONTAINER MACROS (Level 2 — Container Diagrams)
' ============================================================================
' Containers are deployable units: web apps, APIs, databases, message brokers.
!unquoted procedure Container($alias, $label, $techn="", $descr="")
!if ($techn != "" && $descr != "")
rectangle "==$label\n<size:11>[Container: $techn]</size>\n\n<size:11>$descr</size>" <<container>> as $alias $CONTAINER_BG
!elseif ($techn != "")
rectangle "==$label\n<size:11>[Container: $techn]</size>" <<container>> as $alias $CONTAINER_BG
!elseif ($descr != "")
rectangle "==$label\n<size:11>[Container]</size>\n\n<size:11>$descr</size>" <<container>> as $alias $CONTAINER_BG
!else
rectangle "==$label\n<size:11>[Container]</size>" <<container>> as $alias $CONTAINER_BG
!endif
!endprocedure
!unquoted procedure Container_Ext($alias, $label, $techn="", $descr="")
!if ($techn != "" && $descr != "")
rectangle "==$label\n<size:11>[Container: $techn]</size>\n\n<size:11>$descr</size>" <<container_ext>> as $alias $EXTERNAL_BG
!elseif ($techn != "")
rectangle "==$label\n<size:11>[Container: $techn]</size>" <<container_ext>> as $alias $EXTERNAL_BG
!elseif ($descr != "")
rectangle "==$label\n<size:11>[Container]</size>\n\n<size:11>$descr</size>" <<container_ext>> as $alias $EXTERNAL_BG
!else
rectangle "==$label\n<size:11>[Container]</size>" <<container_ext>> as $alias $EXTERNAL_BG
!endif
!endprocedure
!unquoted procedure ContainerDb($alias, $label, $techn="", $descr="")
!if ($techn != "" && $descr != "")
database "==$label\n<size:11>[Database: $techn]</size>\n\n<size:11>$descr</size>" <<container_db>> as $alias $CONTAINER_BG
!elseif ($techn != "")
database "==$label\n<size:11>[Database: $techn]</size>" <<container_db>> as $alias $CONTAINER_BG
!elseif ($descr != "")
database "==$label\n<size:11>[Database]</size>\n\n<size:11>$descr</size>" <<container_db>> as $alias $CONTAINER_BG
!else
database "==$label\n<size:11>[Database]</size>" <<container_db>> as $alias $CONTAINER_BG
!endif
!endprocedure
!unquoted procedure ContainerDb_Ext($alias, $label, $techn="", $descr="")
!if ($techn != "" && $descr != "")
database "==$label\n<size:11>[Database: $techn]</size>\n\n<size:11>$descr</size>" <<container_db_ext>> as $alias $EXTERNAL_BG
!elseif ($techn != "")
database "==$label\n<size:11>[Database: $techn]</size>" <<container_db_ext>> as $alias $EXTERNAL_BG
!elseif ($descr != "")
database "==$label\n<size:11>[Database]</size>\n\n<size:11>$descr</size>" <<container_db_ext>> as $alias $EXTERNAL_BG
!else
database "==$label\n<size:11>[Database]</size>" <<container_db_ext>> as $alias $EXTERNAL_BG
!endif
!endprocedure
!unquoted procedure ContainerQueue($alias, $label, $techn="", $descr="")
!if ($techn != "" && $descr != "")
queue "==$label\n<size:11>[Queue: $techn]</size>\n\n<size:11>$descr</size>" <<container_queue>> as $alias $CONTAINER_BG
!elseif ($techn != "")
queue "==$label\n<size:11>[Queue: $techn]</size>" <<container_queue>> as $alias $CONTAINER_BG
!elseif ($descr != "")
queue "==$label\n<size:11>[Queue]</size>\n\n<size:11>$descr</size>" <<container_queue>> as $alias $CONTAINER_BG
!else
queue "==$label\n<size:11>[Queue]</size>" <<container_queue>> as $alias $CONTAINER_BG
!endif
!endprocedure
!unquoted procedure ContainerQueue_Ext($alias, $label, $techn="", $descr="")
!if ($techn != "" && $descr != "")
queue "==$label\n<size:11>[Queue: $techn]</size>\n\n<size:11>$descr</size>" <<container_queue_ext>> as $alias $EXTERNAL_BG
!elseif ($techn != "")
queue "==$label\n<size:11>[Queue: $techn]</size>" <<container_queue_ext>> as $alias $EXTERNAL_BG
!elseif ($descr != "")
queue "==$label\n<size:11>[Queue]</size>\n\n<size:11>$descr</size>" <<container_queue_ext>> as $alias $EXTERNAL_BG
!else
queue "==$label\n<size:11>[Queue]</size>" <<container_queue_ext>> as $alias $EXTERNAL_BG
!endif
!endprocedure
' ============================================================================
' COMPONENT MACROS (Level 3 — Component Diagrams)
' ============================================================================
' Components are the major structural building blocks within a container.
!unquoted procedure Component($alias, $label, $techn="", $descr="")
!if ($techn != "" && $descr != "")
rectangle "==$label\n<size:11>[Component: $techn]</size>\n\n<size:11>$descr</size>" <<component>> as $alias $COMPONENT_BG
!elseif ($techn != "")
rectangle "==$label\n<size:11>[Component: $techn]</size>" <<component>> as $alias $COMPONENT_BG
!elseif ($descr != "")
rectangle "==$label\n<size:11>[Component]</size>\n\n<size:11>$descr</size>" <<component>> as $alias $COMPONENT_BG
!else
rectangle "==$label\n<size:11>[Component]</size>" <<component>> as $alias $COMPONENT_BG
!endif
!endprocedure
!unquoted procedure Component_Ext($alias, $label, $techn="", $descr="")
!if ($techn != "" && $descr != "")
rectangle "==$label\n<size:11>[Component: $techn]</size>\n\n<size:11>$descr</size>" <<component_ext>> as $alias $EXTERNAL_BG
!elseif ($techn != "")
rectangle "==$label\n<size:11>[Component: $techn]</size>" <<component_ext>> as $alias $EXTERNAL_BG
!elseif ($descr != "")
rectangle "==$label\n<size:11>[Component]</size>\n\n<size:11>$descr</size>" <<component_ext>> as $alias $EXTERNAL_BG
!else
rectangle "==$label\n<size:11>[Component]</size>" <<component_ext>> as $alias $EXTERNAL_BG
!endif
!endprocedure
' ============================================================================
' BOUNDARY MACROS
' ============================================================================
' Boundaries group related elements. Close each boundary with a matching `}`.
'
' Enterprise_Boundary(eb, "My Company") {
' System(s1, "System A")
' }
!unquoted procedure Enterprise_Boundary($alias, $label)
rectangle "==$label\n<size:10>[Enterprise]</size>" <<boundary>> as $alias {
!endprocedure
!unquoted procedure System_Boundary($alias, $label)
rectangle "==$label\n<size:10>[System]</size>" <<boundary>> as $alias {
!endprocedure
!unquoted procedure Container_Boundary($alias, $label)
rectangle "==$label\n<size:10>[Container]</size>" <<boundary>> as $alias {
!endprocedure
!unquoted procedure Boundary($alias, $label, $type="")
!if ($type != "")
rectangle "==$label\n<size:10>[$type]</size>" <<boundary>> as $alias {
!else
rectangle "==$label" <<boundary>> as $alias {
!endif
!endprocedure
' ============================================================================
' DEPLOYMENT NODE MACROS (Level 4 — Deployment Diagrams)
' ============================================================================
' Nodes represent deployment infrastructure. Close each node with `}`.
'
' Node(web, "Web Server", "Ubuntu 22.04") {
' Container(api, "API", "ASP.NET Core")
' }
!unquoted procedure Node($alias, $label, $techn="", $descr="")
!if ($techn != "" && $descr != "")
node "$label\n<size:11>[$techn]</size>\n<size:10>$descr</size>" as $alias {
!elseif ($techn != "")
node "$label\n<size:11>[$techn]</size>" as $alias {
!else
node "$label" as $alias {
!endif
!endprocedure
!unquoted procedure Node_R($alias, $label, $techn="", $descr="")
!if ($techn != "" && $descr != "")
node "$label\n<size:11>[$techn]</size>\n<size:10>$descr</size>" as $alias {
!elseif ($techn != "")
node "$label\n<size:11>[$techn]</size>" as $alias {
!else
node "$label" as $alias {
!endif
!endprocedure
' ============================================================================
' RELATIONSHIP MACROS
' ============================================================================
' Relationships define how elements communicate. Direction suffixes control
' arrow routing: _U(p), _D(own), _L(eft), _R(ight).
'
' Rel(user, api, "Makes API calls to", "JSON/HTTPS")
' Rel_D(api, db, "Reads from and writes to", "SQL/TCP")
!unquoted procedure Rel($from, $to, $label, $techn="")
!if ($techn != "")
$from --> $to : "<size:11>$label</size>\n<size:10>[$techn]</size>"
!else
$from --> $to : "<size:11>$label</size>"
!endif
!endprocedure
!unquoted procedure Rel_U($from, $to, $label, $techn="")
!if ($techn != "")
$from -up-> $to : "<size:11>$label</size>\n<size:10>[$techn]</size>"
!else
$from -up-> $to : "<size:11>$label</size>"
!endif
!endprocedure
!unquoted procedure Rel_D($from, $to, $label, $techn="")
!if ($techn != "")
$from -down-> $to : "<size:11>$label</size>\n<size:10>[$techn]</size>"
!else
$from -down-> $to : "<size:11>$label</size>"
!endif
!endprocedure
!unquoted procedure Rel_L($from, $to, $label, $techn="")
!if ($techn != "")
$from -left-> $to : "<size:11>$label</size>\n<size:10>[$techn]</size>"
!else
$from -left-> $to : "<size:11>$label</size>"
!endif
!endprocedure
!unquoted procedure Rel_R($from, $to, $label, $techn="")
!if ($techn != "")
$from -right-> $to : "<size:11>$label</size>\n<size:10>[$techn]</size>"
!else
$from -right-> $to : "<size:11>$label</size>"
!endif
!endprocedure
!unquoted procedure BiRel($from, $to, $label, $techn="")
!if ($techn != "")
$from <--> $to : "<size:11>$label</size>\n<size:10>[$techn]</size>"
!else
$from <--> $to : "<size:11>$label</size>"
!endif
!endprocedure
!unquoted procedure Rel_Back($from, $to, $label, $techn="")
!if ($techn != "")
$from <.. $to : "<size:11>$label</size>\n<size:10>[$techn]</size>"
!else
$from <.. $to : "<size:11>$label</size>"
!endif
!endprocedure
!unquoted procedure Rel_Back_D($from, $to, $label, $techn="")
!if ($techn != "")
$from <.down. $to : "<size:11>$label</size>\n<size:10>[$techn]</size>"
!else
$from <.down. $to : "<size:11>$label</size>"
!endif
!endprocedure
' ============================================================================
' LAYOUT HELPERS
' ============================================================================
' Invisible arrows that influence element placement without visible connections.
'
' Lay_D(systemA, systemB) ' forces B below A
!unquoted procedure Lay_U($from, $to)
$from -[hidden]up-> $to
!endprocedure
!unquoted procedure Lay_D($from, $to)
$from -[hidden]down-> $to
!endprocedure
!unquoted procedure Lay_L($from, $to)
$from -[hidden]left-> $to
!endprocedure
!unquoted procedure Lay_R($from, $to)
$from -[hidden]right-> $to
!endprocedure
' ============================================================================
' DIAGRAM TYPE HEADERS
' ============================================================================
' Optional title/description helpers. Call at the top of your diagram to add
' a consistent title block.
'
' SHOW_LEGEND()
!unquoted procedure LAYOUT_TOP_DOWN()
top to bottom direction
!endprocedure
!unquoted procedure LAYOUT_LEFT_RIGHT()
left to right direction
!endprocedure
!unquoted procedure SHOW_LEGEND()
legend right
|<$PERSON_BG> <color:$FONT_WHITE>Person</color> |
|<$SYSTEM_BG> <color:$FONT_WHITE>Internal System</color> |
|<$EXTERNAL_BG> <color:$FONT_WHITE>External System</color> |
|<$CONTAINER_BG> <color:$FONT_WHITE>Container</color> |
|<$COMPONENT_BG> Component |
endlegend
!endprocedure
' ============================================================================
' END OF C4 MACRO LIBRARY
' ============================================================================
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment