Convert Mermaid ER to MySQL

Generate production-ready MySQL SQL code from your Mermaid ER diagrams in seconds.

mysql
Dialect: mysqlTables: 2
Done.
mermaid
Live preview mermaid

How the Mermaid ER to MySQL conversion works

MySQL turns Mermaid input into InnoDB-ready DDL with a few dialect-specific habits: string maps to VARCHAR(255) rather than TEXT so columns stay indexable by default, enums are inline column types instead of separate objects, and every identifier is backtick-quoted β€” which is what lets a table named order (a reserved word) work at all.

Mermaid erDiagram is a Markdown-friendly notation rendered natively by GitHub, GitLab, Notion, and Obsidian β€” which makes it the most common way to keep an ER diagram next to the code it describes.

Entities are blocks of `type name marker` lines (markers: PK, FK, UK, INDEX), and relationships use cardinality arrows like `USER ||--o{ POST : writes` β€” one-to-many from USER to POST. The converter reads both, plus comment directives for everything the base syntax can't express.

Paste your Mermaid ER source into the editor above and the engine parses it into an intermediate schema β€” tables, columns, relationships, indexes β€” then generates MySQL 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 Mermaid ER reference documents the full vocabulary.

Worked example: an e-commerce schema

A complete Mermaid ER diagram and the exact MySQL output the generator produces for it β€” different from the starter diagram in the editor above, so you can see a second real conversion end to end:

erDiagram
    CUSTOMER ||--o{ ORDER : places
    PRODUCT ||--o{ ORDER : "ordered in"
    CUSTOMER {
        int id PK
        string email UK
        %% ::NN
        string name
        %% ::DEFAULT(now())
        timestamp created_at
    }
    PRODUCT {
        int id PK
        string sku UK
        %% ::CHECK(price > 0)
        decimal price
        %% ::ENUM(draft, active, retired)
        string status
    }
    ORDER {
        int id PK
        int customer_id FK
        int product_id FK
        %% ::DEFAULT(0)
        decimal total
    }
CREATE TABLE `customer` (
    `id` INT AUTO_INCREMENT PRIMARY KEY,
    `email` VARCHAR(255) UNIQUE,
    `name` VARCHAR(255) NOT NULL,
    `created_at` DATETIME DEFAULT now()
);

CREATE TABLE `order` (
    `id` INT AUTO_INCREMENT PRIMARY KEY,
    `customer_id` INT,
    `product_id` INT,
    `total` DECIMAL DEFAULT 0
);

CREATE TABLE `product` (
    `id` INT AUTO_INCREMENT PRIMARY KEY,
    `sku` VARCHAR(255) UNIQUE,
    `price` DECIMAL CHECK (price > 0),
    `status` ENUM('draft', 'active', 'retired')
);

ALTER TABLE `order`
    ADD CONSTRAINT `fk_order_customer_id`
    FOREIGN KEY (`customer_id`) REFERENCES `customer`(`id`);

ALTER TABLE `order`
    ADD CONSTRAINT `fk_order_product_id`
    FOREIGN KEY (`product_id`) REFERENCES `product`(`id`);

The same diagram that produced a CREATE TYPE on PostgreSQL emits an inline ENUM('draft', 'active', 'retired') column here β€” MySQL's native enum form. AUTO_INCREMENT replaces SERIAL, string became VARCHAR(255), and the foreign keys keep deterministic fk_order_customer_id names, which matters on MySQL where anonymous constraints make later ALTERs painful.

What the generator emits for MySQL

  • CREATE TABLE statements with backtick-quoted identifiers, ready for InnoDB
  • AUTO_INCREMENT primary keys for single integer PK columns
  • inline ENUM(…) column types for ::ENUM(...) columns
  • ALTER TABLE … ADD CONSTRAINT foreign keys with ON DELETE / ON UPDATE actions
  • inline COMMENT column options and COMMENT = table options
  • CREATE INDEX / CREATE UNIQUE INDEX for composite and named indexes

Type mapping: Mermaid ER to MySQL

Diagram column types are logical β€” the generator maps each one to the idiomatic MySQL type. These are the exact mappings the engine uses:

Diagram typeMySQL typeNotes
intINTINT AUTO_INCREMENT when it is the auto-increment primary key
stringVARCHAR(255)use varchar(n) in the diagram to control length
textTEXTlongtext / mediumtext map to their native equivalents
decimalDECIMALdecimal(10,2) passes precision through
booleanTINYINT(1)the MySQL convention for booleans
dateDATE
timestampDATETIME
uuidCHAR(36)stored as the canonical text form
bigintBIGINT
blobBLOB

Keys, relationships, and enums

A single `int id PK` column becomes `` `id` INT AUTO_INCREMENT PRIMARY KEY ``. Composite primary keys emit a table-level `PRIMARY KEY (a, b)` without auto-increment.

Relationships emit `ALTER TABLE … ADD CONSTRAINT` statements with deterministic `fk_<table>_<column>` names β€” important on MySQL, where anonymous constraints make later migrations painful. ON DELETE / ON UPDATE actions come from the ::RELATIONSHIP directive.

MySQL supports enums natively on the column, so `::ENUM(active, inactive)` emits `status ENUM('active', 'inactive')` inline β€” no separate type object, no CHECK constraint.

Frequently asked questions

Why VARCHAR(255) instead of TEXT for string columns?

MySQL can't index a TEXT column without a prefix length, so the generator defaults string to VARCHAR(255). Write varchar(80) (or any length) as the column type in the diagram to control the size, or text to force TEXT.

How does a table named order survive in MySQL?

ORDER is a reserved word, but the generator backtick-quotes every identifier, so `order` is legal. You don't have to rename entities in the diagram to dodge SQL keywords.

Does the generated MySQL DDL use native ENUM columns?

Yes. ::ENUM(...) values are emitted as an inline ENUM(…) column type, which MySQL validates at the storage layer. PostgreSQL output uses CREATE TYPE instead; SQLite and Oracle fall back to CHECK constraints.

How are booleans represented?

As TINYINT(1), the MySQL convention. Most drivers and ORMs read TINYINT(1) back as a boolean automatically.

Related conversions