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.
| Stereotype | Meaning | SQL effect |
|---|---|---|
<<PK>> | Primary key | Auto-increment primary key |
<<FK>> | Foreign key | Foreign key constraint from relationship |
<<UNIQUE>> | Unique | UNIQUE constraint on column |
<<NOT NULL>> | Not null | Equivalent to leading * |
<<INDEX>> | Single-column index | CREATE INDEX |
<<DEFAULT(val)>> | Default value | DEFAULT val |
<<CHECK(expr)>> | CHECK constraint | CHECK (expr) |
<<ENUM(v1,v2)>> | Enum values | Dialect-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"
@endumlSQL (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
| Feature | Mermaid | PlantUML |
|---|---|---|
| NOT NULL | %% ::NN directive | Leading * on column |
| Primary key | PK marker | <<PK>> stereotype |
| Unique | UK marker | <<UNIQUE>> stereotype |
| Default values | %% ::DEFAULT(val) | <<DEFAULT(val)>> or ' ::DEFAULT(val) |
| Comment character | %% | ' |
| Wrapper | erDiagram | @startuml / @enduml |