Convert PlantUML to PostgreSQL
Generate production-ready PostgreSQL SQL code from your PlantUML diagrams in seconds.
How the PlantUML to PostgreSQL conversion works
PlantUML entity diagrams are the standard in many enterprise and Java-adjacent teams, with first-class tooling in IDEs and Confluence. Entities declare mandatory fields with a leading *, and stereotypes like <<FK>> mark key columns.
Entities are `entity Name { … }` blocks — a leading `*` marks mandatory (NOT NULL) fields, `<<FK>>` marks foreign keys, and relationships use the same cardinality arrows as Mermaid (`User ||--o{ Post`). Quoted display names (`entity "User Account" as ua`) become table comments.
Paste your PlantUML source into the editor above and the engine parses it into an
intermediate schema — tables, columns, relationships, indexes — then generates
PostgreSQL DDL from that model. Anything the diagram
syntax can't express (NOT NULL, defaults, enums, CHECK constraints, composite indexes)
you add with comment directives like ' ::NN, ::DEFAULT(now()) on the line
above a column. The PlantUML reference documents the
full vocabulary.
What the generator emits for PostgreSQL
- CREATE TABLE statements with double-quoted identifiers
- SERIAL primary keys for single integer PK columns
- CREATE TYPE … AS ENUM for ::ENUM(...) columns
- ALTER TABLE … ADD CONSTRAINT foreign keys with ON DELETE / ON UPDATE actions
- CREATE INDEX / CREATE UNIQUE INDEX, including partial indexes with a WHERE clause
- COMMENT ON TABLE and COMMENT ON COLUMN for documentation carried over from the diagram
Type mapping: PlantUML to PostgreSQL
Diagram column types are logical — the generator maps each one to the idiomatic PostgreSQL type. These are the exact mappings the engine uses:
| Diagram type | PostgreSQL type | Notes |
|---|---|---|
int | INTEGER | SERIAL when it is the auto-increment primary key |
string | TEXT | use varchar(n) in the diagram for VARCHAR(n) |
text | TEXT | |
decimal | NUMERIC | decimal(10,2) passes precision through |
boolean | BOOLEAN | |
date | DATE | |
timestamp | TIMESTAMPTZ | timezone-aware by default |
uuid | UUID | native PostgreSQL UUID type |
bigint | BIGINT | |
blob | BYTEA |
Keys, relationships, and enums
A single `int id PK` column becomes `"id" SERIAL PRIMARY KEY`. Composite primary keys (e.g. on junction tables) emit a table-level `PRIMARY KEY (a, b)` clause without auto-increment.
Relationships emit `ALTER TABLE … ADD CONSTRAINT fk_<table>_<column> FOREIGN KEY … REFERENCES …` after all tables are created, so declaration order never matters. `::RELATIONSHIP[onDelete: CASCADE]` adds the corresponding ON DELETE action.
PostgreSQL gets a real enum: `::ENUM(active, inactive)` emits `CREATE TYPE status_enum AS ENUM ('active', 'inactive')` before the table, and the column uses that type. This gives you database-level validation without CHECK constraints.
Frequently asked questions
How are enums handled in the generated PostgreSQL DDL?
With native CREATE TYPE … AS ENUM statements. The enum type is created before the table that uses it, and the column references the type — not a CHECK constraint or a plain VARCHAR.
Does the converter use SERIAL or IDENTITY columns?
SERIAL. A single integer primary key becomes SERIAL PRIMARY KEY (BIGSERIAL for bigint). Columns that are both PK and FK — the one-to-one child pattern — stay plain INTEGER so the value can mirror the parent key.
Are timestamps timezone-aware?
Yes — the abstract timestamp type maps to TIMESTAMPTZ. If you need a naive timestamp, declare the column type explicitly in the diagram.
Can I add CHECK constraints and partial indexes from the diagram?
Yes. `::CHECK(price > 0)` emits an inline CHECK, and `::INDEX([email], where: "deleted_at IS NULL")` emits a partial index with a WHERE clause — both PostgreSQL-native features the converter supports directly.