Mermaid exampleEntity Relationship

E-commerce Database ER Diagram with Orders and Payments

An entity-relationship diagram for a store is the first thing a backend team draws before writing migrations. It fixes the questions that cause rewrites later: can an order exist without a payment, can a product be in many categories, and where does the price at time of purchase live.

  • ecommerce er diagram
  • online store database schema
  • mermaid erdiagram example
  • orders products schema
  • entity relationship diagram
E-commerce Database ER Diagram with Orders and Payments

has

places

contains

paid by

appears in

groups

CUSTOMER

int

id

PK

string

email

UK

ADDRESS

ORDER

int

id

PK

int

customer_id

FK

string

status

decimal

total

ORDER_ITEM

int

id

PK

int

order_id

FK

int

product_id

FK

int

quantity

decimal

unit_price

PAYMENT

PRODUCT

CATEGORY

Open in editor → 24 linesrenders in GitHub, Notion, Obsidian

Mermaid code

erDiagram
    CUSTOMER ||--o{ ADDRESS : has
    CUSTOMER ||--o{ ORDER : places
    ORDER ||--|{ ORDER_ITEM : contains
    ORDER ||--o| PAYMENT : "paid by"
    PRODUCT ||--o{ ORDER_ITEM : "appears in"
    CATEGORY ||--o{ PRODUCT : groups
    CUSTOMER {
        int id PK
        string email UK
    }
    ORDER {
        int id PK
        int customer_id FK
        string status
        decimal total
    }
    ORDER_ITEM {
        int id PK
        int order_id FK
        int product_id FK
        int quantity
        decimal unit_price
    }

Paste this into any tool that renders Mermaid, or into the editor to change the theme and export PNG or SVG. Syntax reference: Entity Relationship guide.

What this diagram shows

The relationship lines at the top carry the rules. CUSTOMER ||--o{ ORDER reads as one customer places zero or more orders. ORDER ||--|{ ORDER_ITEM requires at least one item per order. ORDER ||--o| PAYMENT allows an unpaid order with at most one payment. ORDER_ITEM stores unit_price so a later price change on PRODUCT does not rewrite history. ADDRESS, CATEGORY, PRODUCT, and PAYMENT are declared through relationships only, which keeps the diagram focused on the order path; add attribute blocks for them as your schema settles.

How to adapt it

  • Change ORDER ||--o| PAYMENT to ORDER ||--o{ PAYMENT if you support split or retried payments.
  • Add a PRODUCT_CATEGORY join entity and make CATEGORY }o--o{ PRODUCT if products belong to several categories.
  • Add an ADDRESS attribute block with int customer_id FK and string type to distinguish billing from shipping addresses.
  • Rename string status to an explicit list in a comment, for example %% status: pending, paid, shipped, cancelled, so the allowed values travel with the diagram.
  • Add INVENTORY with int product_id FK and int on_hand if stock is tracked per warehouse.

FAQ

Why does ORDER_ITEM repeat the price when PRODUCT already has one?

Because the product price changes and past orders must not. Copying unit_price into the line item at checkout is the standard fix. The diagram makes that decision visible by giving both entities a price attribute.

What does the crow's foot notation mean in Mermaid?

Each side of the connector has two characters. || is exactly one, o| is zero or one, }| is one or more, and o{ is zero or more. The left pair describes the left entity's side, the right pair the right entity's side.

Can I show indexes or unique constraints?

Mermaid supports PK, FK, and UK as attribute key markers. Use string email UK to mark a unique column. Indexes that are not constraints have no syntax; put them in a comment line starting with %%.