Skip to content

Instantly share code, notes, and snippets.

@sualeh
Last active October 23, 2025 05:35
Show Gist options
  • Select an option

  • Save sualeh/ea272410356527d3132809061e8ba5b4 to your computer and use it in GitHub Desktop.

Select an option

Save sualeh/ea272410356527d3132809061e8ba5b4 to your computer and use it in GitHub Desktop.
Create Nice-looking Schema Diagrams in PlantUML

Create Nice-looking Schema Diagrams in PlantUML

PlantUML is a descriptive language to generate a number of types of software diagrams, such as sequence, class, deployment and state diagrams, and many others. PlantUML does not generate very good-looking schema diagrams out of the box, but it supports themes and preprocessed macros. If you use themes and macros, you can not only use a simplified syntax, but also generate beautiful diagrams.

Here is an example of a PlantUML schema diagram, and we will build up the code to generate it.

Schema diagram

To start, describe your schemas, tables and columns using this syntax as an example.

$schema("PUBLISHER_SALES", "id_7f7f6c20") {

  $table("SALES", "id_751e68cc") {
    $column("POSTALCODE"): VARCHAR NOT NULL
    $column("COUNTRY"): VARCHAR NOT NULL
    $fk("BOOKID"): INTEGER
    $fk("COUPON_ID"): INTEGER
    $column("PERIODENDDATE"): DATE
    $column("TOTALAMOUNT"): DOUBLE
  }

}

You can pick any id, as long as it is unique across the diagram. This will allow you to have tables with the same name in different schemas.

Then, using those ids, you can define foreign key relationships like this:

id_208b5502.id_f521e766::ID  ||--o{ id_208b5502.id_ead84c5d::AUTHORID : FK_AUTHOR

The secret sauce to this meta-language is in the file header, and it looks like this:

!theme plain
hide empty methods

!procedure $schema($name, $slug)
package "$name" as $slug <<Rectangle>>
!endprocedure

!procedure $table($name, $slug)
entity "<b>$name</b>" as $slug << (T, Orange) table >>
!endprocedure

!procedure $view($name, $slug)
entity "<b>$name</b>" as $slug << (V, Aquamarine) view >>
!endprocedure

!procedure $pk($name)
<color:#GoldenRod><&key></color> <b>$name</b>
!endprocedure

!procedure $fk($name)
<color:#Silver><&key></color> $name
!endprocedure

!procedure $column($name)
{field} <color:#White><&media-record></color> $name
!endprocedure

Here is an example file with everything put together. You can visualize diagram this online using PlantText editor, and then create your own.

Take a look at SchemaCrawler, which extends functionality by connecting to your database server and generating a PlantUML schema diagram from it using this technique.

@startuml
!theme plain
hide empty methods
!procedure $schema($name, $slug)
package "$name" as $slug <<Rectangle>>
!endprocedure
!procedure $table($name, $slug)
entity "<b>$name</b>" as $slug << (T, Orange) table >>
!endprocedure
!procedure $view($name, $slug)
entity "<b>$name</b>" as $slug << (V, Aquamarine) view >>
!endprocedure
!procedure $pk($name)
<color:#GoldenRod><&key></color> <b>$name</b>
!endprocedure
!procedure $fk($name)
<color:#Silver><&key></color> $name
!endprocedure
!procedure $column($name)
{field} <color:#White><&media-record></color> $name
!endprocedure
title "Publications Schema"
$schema("PUBLICATIONS", "id_208b5502") {
$table("AUTHORS", "id_f521e766") {
$pk("ID"): INTEGER NOT NULL
$column("FIRSTNAME"): VARCHAR NOT NULL
$column("LASTNAME"): VARCHAR NOT NULL
$column("ADDRESS1"): VARCHAR
$column("ADDRESS2"): VARCHAR
$column("CITY"): VARCHAR
$column("STATE"): CHARACTER
$column("POSTALCODE"): VARCHAR
$column("COUNTRY"): VARCHAR
}
$table("BOOKS", "id_f4a675c8") {
$pk("ID"): INTEGER NOT NULL
$column("TITLE"): VARCHAR NOT NULL
$column("DESCRIPTION"): VARCHAR
$column("PUBLISHERID"): INTEGER NOT NULL
$column("PUBLICATIONDATE"): DATE
$column("PRICE"): DOUBLE
}
$table("BOOKAUTHORS", "id_ead84c5d") {
$fk("BOOKID"): INTEGER NOT NULL
$fk("AUTHORID"): INTEGER NOT NULL
$column("SOMEDATA"): VARCHAR
}
}
$schema("PUBLISHER_SALES", "id_7f7f6c20") {
$table("SALES", "id_751e68cc") {
$column("POSTALCODE"): VARCHAR NOT NULL
$column("COUNTRY"): VARCHAR NOT NULL
$fk("BOOKID"): INTEGER
$fk("COUPON_ID"): INTEGER
$column("PERIODENDDATE"): DATE
$column("TOTALAMOUNT"): DOUBLE
}
}
id_208b5502.id_f521e766::ID ||--o{ id_208b5502.id_ead84c5d::AUTHORID : FK_AUTHOR
id_208b5502.id_f4a675c8::ID ||--o{ id_7f7f6c20.id_751e68cc::BOOKID : FK_SALES_BOOK
id_208b5502.id_f4a675c8::ID ||--o{ id_208b5502.id_ead84c5d::BOOKID : FK_BOOK
@enduml
@rodw
Copy link

rodw commented Oct 23, 2025

Nice!

Just a quick suggestion: if the intent behind the <color:#White> bit in line 27:

{field} <color:#White><&media-record></color> $name

is to "hide" the &media-record icon in order to align with the &key as used in the $pk() and $fk() cases (which it does when the !theme plain directive is in place, as seen in schema.png rendering) then you might want to use <color:#transparent> instead.

(transparent is a valid color name per https://plantuml.com/color, equivalent to #00000000)

That way the icon is still hidden, even if a non-white background color is used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment