Entity Relationship Diagrams with Mermaid.js

Design database schemas with Mermaid.js ER diagrams. Learn entities, attributes, relationships, cardinality, and best practices for data modeling.

What Are ER Diagrams?

Entity Relationship Diagrams (ERDs) visualize database structure — the tables (entities), their columns (attributes), and how they relate to each other. They're essential for:

- Designing new databases

- Documenting existing schemas

- Communicating data models to team members

- Planning migrations and refactors

Mermaid's ER diagram syntax lets you create these diagrams as code, keeping your data documentation in sync with your actual schema.

Basic Syntax

erDiagram
    CUSTOMER {
        int id PK
        string name
        string email
    }
    ORDER {
        int id PK
        date created_at
        int customer_id FK
    }
    CUSTOMER ||--o{ ORDER : places
Try in Editor →

Key elements:

  • Entities are defined with their name and attributes in curly braces
  • Attributes have a type, name, and optional constraint (PK, FK, UK)
  • Relationships use special notation for cardinality

Attribute Syntax

Each attribute follows the pattern: type name constraint "comment"

erDiagram
    USER {
        int id PK "Auto-increment primary key"
        string username UK "Unique username"
        string email UK "Unique email address"
        string password_hash "Bcrypt hashed"
        datetime created_at "Default: now()"
        datetime updated_at "Updated on change"
        boolean is_active "Default: true"
    }
Try in Editor →

Supported Constraints

  • PK — Primary Key
  • FK — Foreign Key
  • UK — Unique Key

Relationship Cardinality

Mermaid uses a notation combining two symbols — one for each end:

erDiagram
    A ||--|| B : "one to one"
    C ||--o{ D : "one to many"
    E }o--o{ F : "many to many"
    G ||--o| H : "one to zero or one"
Try in Editor →

Notation Guide

Left/right symbols:

- || — exactly one

- o| — zero or one

- }| — one or more

- }o — zero or more

The line style:

- -- — solid line (identifying relationship)

- .. — dashed line (non-identifying relationship)

Common Patterns

erDiagram
    %% One-to-many (most common)
    AUTHOR ||--o{ BOOK : writes

    %% Many-to-many (via junction table)
    STUDENT }o--o{ COURSE : enrolls_in

    %% One-to-one
    USER ||--|| PROFILE : has

    %% Optional relationship
    EMPLOYEE ||--o| PARKING_SPOT : assigned
Try in Editor →

Practical Example: Blog Platform

erDiagram
    USER {
        int id PK
        string username UK
        string email UK
        string password_hash
        string avatar_url
        text bio
        datetime created_at
    }

    POST {
        int id PK
        string title
        string slug UK
        text content
        string status "draft|published|archived"
        int author_id FK
        datetime published_at
        datetime created_at
        datetime updated_at
    }

    COMMENT {
        int id PK
        text body
        int post_id FK
        int author_id FK
        int parent_id FK "For nested comments"
        datetime created_at
    }

    TAG {
        int id PK
        string name UK
        string slug UK
    }

    POST_TAG {
        int post_id FK
        int tag_id FK
    }

    LIKE {
        int id PK
        int user_id FK
        int post_id FK
        datetime created_at
    }

    USER ||--o{ POST : writes
    USER ||--o{ COMMENT : writes
    POST ||--o{ COMMENT : has
    COMMENT ||--o{ COMMENT : replies_to
    POST ||--o{ POST_TAG : has
    TAG ||--o{ POST_TAG : tagged
    USER ||--o{ LIKE : gives
    POST ||--o{ LIKE : receives
Try in Editor →

Practical Example: E-Commerce Database

erDiagram
    CUSTOMER {
        int id PK
        string first_name
        string last_name
        string email UK
        string phone
        datetime created_at
    }

    ADDRESS {
        int id PK
        int customer_id FK
        string street
        string city
        string state
        string zip_code
        string country
        boolean is_default
    }

    PRODUCT {
        int id PK
        string name
        string sku UK
        text description
        decimal price
        int stock_quantity
        int category_id FK
        boolean is_active
    }

    CATEGORY {
        int id PK
        string name
        int parent_id FK "Self-referencing for hierarchy"
    }

    ORDERS {
        int id PK
        int customer_id FK
        int shipping_address_id FK
        string status
        decimal subtotal
        decimal tax
        decimal total
        datetime ordered_at
    }

    ORDER_ITEM {
        int id PK
        int order_id FK
        int product_id FK
        int quantity
        decimal unit_price
        decimal subtotal
    }

    PAYMENT {
        int id PK
        int order_id FK
        string method
        string status
        decimal amount
        string transaction_id UK
        datetime paid_at
    }

    CUSTOMER ||--o{ ADDRESS : has
    CUSTOMER ||--o{ ORDERS : places
    ORDERS ||--|{ ORDER_ITEM : contains
    ORDERS ||--|| PAYMENT : paid_by
    ORDERS }o--|| ADDRESS : ships_to
    ORDER_ITEM }o--|| PRODUCT : references
    PRODUCT }o--|| CATEGORY : belongs_to
    CATEGORY ||--o{ CATEGORY : parent_of
Try in Editor →

Practical Example: SaaS Multi-Tenant

erDiagram
    TENANT {
        int id PK
        string name
        string subdomain UK
        string plan "free|pro|enterprise"
        datetime created_at
    }

    USER {
        int id PK
        int tenant_id FK
        string email
        string role "admin|member|viewer"
        datetime last_login
    }

    PROJECT {
        int id PK
        int tenant_id FK
        string name
        text description
        int owner_id FK
    }

    TASK {
        int id PK
        int project_id FK
        string title
        text description
        string status "todo|doing|done"
        int assignee_id FK
        date due_date
    }

    TENANT ||--o{ USER : has
    TENANT ||--o{ PROJECT : owns
    USER ||--o{ PROJECT : manages
    PROJECT ||--o{ TASK : contains
    USER ||--o{ TASK : assigned
Try in Editor →

Tips for Data Modeling with Mermaid

1. Start with Entities

List your main entities first without attributes. Map out the relationships. Then add attributes.

2. Name Relationships Clearly

The label after the colon describes the relationship: CUSTOMER ||--o{ ORDER : places. Use active verbs: "places", "contains", "belongs_to", "writes".

3. Show Junction Tables

For many-to-many relationships, explicitly show the junction table:

erDiagram
    STUDENT }o--o{ COURSE : enrolls_in
Try in Editor →

Or with the junction table visible:

erDiagram
    STUDENT ||--o{ ENROLLMENT : has
    COURSE ||--o{ ENROLLMENT : has
    ENROLLMENT {
        int student_id FK
        int course_id FK
        date enrolled_at
        string grade
    }
Try in Editor →

The second approach is better when the junction table has its own attributes.

4. Include Data Types

Always specify types — it makes the diagram useful for actual implementation:

- int, bigint — IDs, counts

- string or varchar — text fields

- text — long content

- decimal — money, precise numbers

- boolean — flags

- datetime, date, timestamp — temporal data

- json or jsonb — flexible structured data

5. Mark Constraints

Always mark PK, FK, and UK. These are the most important structural information in a schema diagram.

6. Use Comments for Business Rules

Add comments in quotes to document constraints that aren't visible in the structure:

erDiagram
    ORDER {
        string status "Enum: pending|processing|shipped|delivered|cancelled"
        decimal total "Computed: sum of line items + tax"
    }
Try in Editor →

Common Mistakes

  • Missing foreign keys — Every relationship line should have a corresponding FK attribute.
  • Wrong cardinality — Think carefully: can a customer have zero orders? Then it's ||--o{ not ||--|{.
  • Tables without relationships — If an entity has no relationships, it might not belong in the diagram, or you're missing a connection.
  • Too many entities — Focus on one bounded context. A diagram with 30+ tables is overwhelming.

Conclusion

Mermaid ER diagrams are perfect for documenting database schemas in your project repository. They render on GitHub, stay version-controlled, and are easy to update when your schema evolves. Start with the core entities and relationships, then progressively add attributes and constraints as your model matures.

Try it now in our free Mermaid Live Editor →