An ER diagram (entity relationship diagram) maps the data structures of a system: the entities you store, the attributes each entity has, and the relationships between them. To design a good one: identify entities from nouns in your requirements, define relationships by their cardinality (one-to-one, one-to-many, many-to-many), resolve many-to-many links with junction tables, and keep attributes inside the entity they describe.
ER diagrams are the blueprint step between "we need to store orders and users" and an actual database schema. This guide covers the notation, a repeatable design process, the mistakes that produce painful schemas, and how to generate an ER diagram from a plain-language description with an AI diagram generator.
ER diagrams answer "what data does this system keep, and how does it connect?" They are standard practice for:
If a flowchart describes process logic and a sequence diagram describes message flow over time, the ER diagram describes persistent structure. Most backend designs need all three; the ER diagram is the one that outlives the project in your schema files.
Three building blocks cover almost every diagram:
| Element | What it looks like | Meaning |
|---|---|---|
| Entity | Rectangle with a title row | A thing you store data about ("USER", "ORDER") |
| Attribute | Row inside the rectangle | A field of that entity ("id", "email") |
| Relationship | Line between entities, with crow's feet | How entities connect, and how many |
The line endings (called cardinality) carry the important information. The common crow's foot notation reads:
Mermaid's erDiagram syntax uses compact labels like ||--o{ (one to zero-or-many). You do not need to memorize every glyph — what matters is being able to state each relationship as a sentence: "A USER places zero or many ORDERS; an ORDER contains one or many ITEMS."
Read your requirements and underline the nouns that need persistent data: "user", "order", "product", "payment". Each one that needs its own records becomes an entity. Nouns that only describe another entity ("order status") become attributes instead. If you find yourself storing the same kind of row twice, you probably have one entity wearing two names.
For each pair of related entities, write the relationship in plain language with a cardinality: "a customer places zero or many orders". If you cannot say the sentence, the relationship is not understood yet — and it will be wrong in the schema too. These sentences translate one-to-one into crow's foot lines.
"Students enroll in many courses; courses have many students" cannot be stored directly in a relational database. Create a junction entity (ENROLLMENT) that holds the pair plus any relationship-specific data (enrolled_at, grade). On the diagram this turns one tangled many-to-many line into two clean one-to-many lines — and in the schema it becomes the join table.
A common temptation is putting user_email on the ORDER entity "for convenience". Duplicated attributes drift out of sync. Store each fact once, in the entity that owns it, and let relationships carry the lookups. Derived values (totals, counts) also do not belong on the diagram — they are computed, not stored.
Every entity needs a primary key (id). Every relationship needs a foreign key on the "many" side (orders.user_id). Mark these on the diagram before decorating with optional fields — if the key structure is wrong, no amount of nice columns will save the schema.
Here is a compact e-commerce model using the rules above — junction entity included:
erDiagram
USER ||--o{ ORDER : places
ORDER ||--|{ ORDER_ITEM : contains
PRODUCT ||--o{ ORDER_ITEM : "is in"
USER {
string id PK
string email
string name
}
ORDER {
string id PK
string user_id FK
string status
}
ORDER_ITEM {
string order_id FK
string product_id FK
int quantity
}
PRODUCT {
string id PK
string title
decimal price
}
Read it in sentences: a user places zero or many orders; an order contains one or many line items; each line item refers to one product. The many-to-many between orders and products is resolved by ORDER_ITEM, which also carries the relationship's own data (quantity). This diagram is valid Mermaid — paste it into any renderer, or into AI Diagram, to see it drawn.
Hand-writing the syntax is precise but slow — every entity, key and relationship is a line of notation. The faster path is describing the model in plain language: "users place orders, each order has line items referencing products, a line item stores quantity" — and an AI ER diagram generator produces the diagram above, rendering live as the code streams in. Refine conversationally ("add a coupon entity, one order can use at most one coupon"), and the result stays standard Mermaid: editable by hand, renderable in GitHub and Notion, exportable to watermark-free PNG/SVG for design docs.
They look similar (boxes with fields and lines) but model different layers: an ER diagram describes persisted data (tables, keys, rows), while a class diagram describes code structure (classes, methods, inheritance). A single feature often has both — the ER diagram for storage and the class diagram for logic.
The most common ER notation, where line endings show cardinality: a bar for "one", a three-pronged fork for "many", a circle for "optional". It reads as sentences: USER ||--o{ ORDER means "one user, zero or many orders".
Add a junction entity in the middle that stores the pairs (and any relationship-specific fields). "Students ↔ courses" becomes "enrollment belongs to one student and one course" — two one-to-many relationships and, later, a join table.
Yes. Describe your entities and relationships in plain language and AI Diagram renders the ER diagram live, keeps it conversationally editable, and exports watermark-free PNG/SVG — useful for design docs, reviews and onboarding new developers. New to Mermaid itself? The Mermaid primer covers how text-to-diagram works and where AI fits in.