Answer: Start with erDiagram, list each table with its columns and PK, FK or UK markers, and join tables with crow's-foot lines like CUSTOMER ||--o{ ORDER : places. The diagram redraws as you type, and you can export it as SVG or PNG. It's free, with no signup.
Type Mermaid syntax, get an entity relationship diagram — live
erDiagram on line one, entity blocks like CUSTOMER { int id PK }, then relationship lines such as CUSTOMER ||--o{ ORDER : places — exactly one customer places zero-or-more orders. This maker renders the MIT-licensed Mermaid 11 library locally in your browser and exports SVG or PNG.
Not in this tool. There's no SQL import, so you type the entities yourself. It's quick, though: each CREATE TABLE becomes an entity block, each column becomes a line like int customer_id FK, and each REFERENCES clause becomes one relationship line. A 10-table schema usually takes a few minutes, and you end up with a text file you can keep next to your migrations.
Both use the dark theme you see in the preview. The PNG is drawn at twice the diagram's size on a dark background, so it stays sharp on slides and high-resolution screens. The SVG scales to any size and drops straight into Confluence, Notion, GitHub READMEs and most design docs. If you need a light version, paste the code into any Mermaid editor set to the default theme.
| Syntax | What it draws |
|---|---|
erDiagram | Required first line |
CUSTOMER { ... } | Entity block (attribute rows go inside) |
int id PK | Attribute row: type, name, key marker |
int customer_id FK | Foreign key badge |
string email UK | Unique / alternate key badge |
string note "free text" | Quoted comment on an attribute |
A ||--|| B : has | One-to-one |
A ||--o{ B : contains | One-to-zero-or-more |
A |{--|{ B : requires | One-or-more to one-or-more |
A o|--o| B : maybe | Zero-or-one to zero-or-one |
A }o--o{ B : links | Many-to-many (both sides crow's feet) |
Read the cardinality symbols in pairs: || exactly one, o| zero-or-one, |{ one-or-more, o{ zero-or-more. The left pair describes the left entity's count of the right one, and the right pair the reverse. Types before names are free-form — write whatever your database actually uses.
An entity relationship diagram is the map of stored data: which tables exist, which columns identify rows, and how many of each side a connection allows. It earns its keep at design time — before the first migration — and later as the picture new engineers orient by. Because it describes structure rather than behavior, it pairs naturally with a class diagram for the code that reads and writes these tables.
Edit on the left; the preview re-renders about 400 ms after you pause, with parse errors shown under the editor. Export SVG for wikis and design docs, PNG for slides. Everything runs locally in your browser.
The default diagram is a small storefront schema. Count it out: 5 entities, 4 relationships, 4 primary keys. The chain CUSTOMER ||--o{ ORDER ||--|{ LINE_ITEM, with PRODUCT ||--o{ LINE_ITEM hanging off the side, is the classic order spine — one customer places many orders, each order contains one-or-more line items, and each line item points back to exactly one product. LINE_ITEM carries a composite identity: both order_id and product_id are FK, which is how a join table with attributes is usually modeled.
erDiagram — the type declarationCUSTOMER ||--o{ ORDER : places — crow's-foot one-to-manystring email UK — unique key badge on the attribute rowCATEGORY ||--o{ PRODUCT : "sorts into" — quote any label that has spacesRenaming a column or flipping a cardinality is a one-line edit followed by an automatic redraw, which is why text-based ERDs stay closer to the real schema than hand-drawn ones ever do.
Each end of a relationship line gets a two-character marker. The outer character is the maximum and the inner one is the minimum, so you read o{ as "zero, or many".
| Left end | Right end | Means | Typical use |
|---|---|---|---|
|o | o| | Zero or one | An optional profile, a nullable foreign key |
|| | || | Exactly one | The parent side of almost every relationship |
}o | o{ | Zero or more | A customer who may not have ordered yet |
}| | |{ | One or more | An order that must have at least one line item |
The middle of the line matters too. Two dashes (--) draw a solid line for an identifying relationship, where the child can't exist without the parent. Two dots (..) draw a dashed line for a non-identifying one, where the child has its own identity, such as PRODUCT }o..o{ TAG : "tagged with".
| Relationship | What to type | In the database |
|---|---|---|
| One-to-one | USER ||--o| PROFILE : has | PROFILE.user_id is FK and also unique |
| One-to-many | CUSTOMER ||--o{ ORDER : places | ORDER.customer_id is FK |
| Many-to-many | STUDENT ||--o{ ENROLLMENT : hasCOURSE ||--o{ ENROLLMENT : has | A join table holds both FKs |
| Self-reference | EMPLOYEE |o--o{ EMPLOYEE : manages | EMPLOYEE.manager_id points at the same table |
You can draw many-to-many directly as }o--o{, and it's fine for an early sketch. Once you're designing real tables, swap it for the join table, because that's what the database will actually contain, and the join table is where attributes like enrolled_on or qty end up.
There's no SQL import, but the translation is mechanical. Take CREATE TABLE orders (id INT PRIMARY KEY, customer_id INT REFERENCES customers(id), placed_on DATE). It becomes an ORDER block with int id PK, int customer_id FK and date placed_on, plus one line, CUSTOMER ||--o{ ORDER : places, for the REFERENCES clause. Each foreign key in your schema is one relationship line. A column that's both part of the key and a reference takes both markers, written int order_id PK, FK, and you can add a short note in quotes after the key, like string email UK "login name".
A ||--o{ B on its own is a parse error, so add : has if nothing better comes to mind.erDiagram, written exactly like that.{ on the entity's line and closes with } on its own line.Parse errors appear under the editor with the line number, so the fastest fix is usually to read that line and the one before it.
Start the first line with erDiagram, define each entity as a block listing its attributes with key markers (int id PK, string email UK), then connect entities with relationship lines like CUSTOMER ||--o{ ORDER : places. This maker renders live in your browser with crow's-foot notation and exports SVG or PNG — free, no signup, nothing uploaded.
It is crow's-foot cardinality read left to right: || means exactly one, o{ means zero-or-more. So CUSTOMER ||--o{ ORDER : places says each customer places zero or more orders, and each order belongs to exactly one customer. Other endings: |{ one-or-more, || exactly one, o| zero-or-one. The two halves sit on either side of the double dash, one for each direction.
Put the key marker after the attribute name inside the entity block: int id PK for primary key, int customer_id FK for foreign key, string email UK for a unique (alternate) key. Mermaid renders the marker as a small badge on that attribute row. Composite keys list PK on two lines.
The type is free-form text before the attribute name — string, int, float, bool, date, or anything your stack calls it (varchar(255), uuid, decimal(10,2) all render fine). Mermaid does not validate types; it prints them exactly as written, so use the names your actual database uses to keep the diagram honest.
An ER diagram models persisted data: tables or entities, their attributes, and the cardinality of the links between them. A class diagram models code: classes with behavior (methods) and object relationships like inheritance. Overlap exists — a Customer appears in both — but methods belong to class diagrams and PK/FK badges belong to ER diagrams.