PlantUML Syntax

Diagram2Code parses PlantUML entity blocks. The @startuml / @enduml wrapper is required. Like Mermaid, PlantUML support is extended with ' comment directives for SQL metadata that standard PlantUML cannot express.

Basic Structure

@startuml
entity EntityName {
  * mandatory_col : type <<PK>>
    optional_col  : type
}
EntityA ||--o{ EntityB : "label"
@enduml

Column Definitions

Column syntax: [*] name : type [<<stereotype>>] ["comment"]

  • A leading * marks the column as NOT NULL (mandatory).
  • No leading * means nullable.
  • Stereotypes in <<>> add SQL constraints.
StereotypeMeaningSQL effect
<<PK>>Primary keyAuto-increment primary key
<<FK>>Foreign keyForeign key constraint from relationship
<<UNIQUE>>UniqueUNIQUE constraint on column
<<NOT NULL>>Not nullEquivalent to leading *
<<INDEX>>Single-column indexCREATE INDEX
<<DEFAULT(val)>>Default valueDEFAULT val
<<CHECK(expr)>>CHECK constraintCHECK (expr)
<<ENUM(v1,v2)>>Enum valuesDialect-appropriate enum

Complete Example

PlantUML
@startuml
entity User {
  * id    : int <<PK>>
  * email : string <<UNIQUE>> "Login email"
  * name  : string
    bio   : text
}

entity Post {
  * id      : int <<PK>>
  * user_id : int <<FK>>
  * title   : string
    body    : text
}

User ||--o{ Post : "writes"
@enduml
SQL (PostgreSQL)
CREATE TABLE "user" (
    "id"    SERIAL PRIMARY KEY,
    "email" TEXT NOT NULL UNIQUE,
    "name"  TEXT NOT NULL,
    "bio"   TEXT
);

CREATE TABLE "post" (
    "id"      SERIAL PRIMARY KEY,
    "user_id" INTEGER NOT NULL,
    "title"   TEXT NOT NULL,
    "body"    TEXT
);

ALTER TABLE "post"
    ADD CONSTRAINT "fk_post_user_id"
    FOREIGN KEY ("user_id")
    REFERENCES "user"("id");

Relationships

PlantUML relationship syntax mirrors Mermaid:

Entity1 ||--o{ Entity2 : "label"
Entity1 |o..o{ Entity2 : "optional"

Solid lines (--) = identifying. Dashed lines (..) = non-identifying. Both produce the same SQL.

' Directives

Use ' comment lines with :: prefix inside entity blocks for SQL metadata that stereotypes cannot express.

Composite indexes

PlantUML
entity Order {
  * id         : int <<PK>>
  * user_id    : int <<FK>>
    created_at : timestamp
  ' ::INDEX([user_id, created_at])
  ' ::UNIQUE([user_id, created_at])
}
SQL
CREATE INDEX "idx_order_user_id_created_at"
    ON "order" ("user_id", "created_at");
CREATE UNIQUE INDEX "uq_order_user_id_created_at"
    ON "order" ("user_id", "created_at");

FK cascade actions

PlantUML
' ::RELATIONSHIP[onDelete: CASCADE]
User ||--o{ Order : "places"
' ::RELATIONSHIP[onDelete: SET NULL]
Dept ||--o{ Emp : "employs"
SQL
FOREIGN KEY ("user_id")
    REFERENCES "user"("id")
    ON DELETE CASCADE;
FOREIGN KEY ("dept_id")
    REFERENCES "dept"("id")
    ON DELETE SET NULL;

Block-level directives — @col::

entity User {
  * id    : int    <<PK>>
  * email : string <<UNIQUE>>
    phone : string
  ' @email::UK(name: "uq_user_email")
  ' @phone::NN
}

Global directives — @TABLE::col::

' @User::email::UK(name: "uq_user_email")
' @User::phone::NN

Key Differences from Mermaid

FeatureMermaidPlantUML
NOT NULL%% ::NN directiveLeading * on column
Primary keyPK marker<<PK>> stereotype
UniqueUK marker<<UNIQUE>> stereotype
Default values%% ::DEFAULT(val)<<DEFAULT(val)>> or ' ::DEFAULT(val)
Comment character%%'
WrappererDiagram@startuml / @enduml