Installs into .claude/skills of the current project.
Are you the author of Mermaid Erd Creation?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/snoodleboot-io-mermaid-erd-creation)
---
name: mermaid-erd-creation
description: Comprehensive guide for creating entity relationship diagrams using Mermaid syntax
languages: [all]
subagents: [architect/data-model, architect/scaffold]
tools_needed: [write]
---
## Mermaid ERD Creation Guide
Entity Relationship Diagrams (ERDs) visualize database schemas and relationships between entities. Use Mermaid syntax for all ERD diagrams in this project.
---
## Basic Syntax
### Minimal ERD Example
```mermaid
erDiagram
USER {
uuid id PK
string email
timestamp created_at
}
ORDER {
uuid id PK
uuid user_id FK
string status
}
USER ||--o{ ORDER : "places"
```
### Entity Declaration
**Format:** `ENTITY_NAME { }`
Rules:
- Entity names in UPPERCASE (e.g., `USER`, `ORDER`, `PAYMENT`)
- Use singular nouns (USER not USERS)
- Avoid abbreviations unless industry-standard (e.g., `OAUTH_TOKEN` is fine)
### Field Declaration
**Format:** `type name constraint`
**Components:**
1. **Type** - Data type (string, int, uuid, timestamp, boolean, decimal, text, json)
2. **Name** - Field name in snake_case
3. **Constraint** - PK (primary key), FK (foreign key), UK (unique key), or empty
**Examples:**
```mermaid
erDiagram
USER {
uuid id PK
string email UK
string password_hash
timestamp created_at
timestamp updated_at
boolean is_active
int login_count
}
```
### Relationship Declaration
**Format:** `ENTITY_A CARDINALITY ENTITY_B : "relationship_label"`
**Cardinality Symbols:**
- `||--||` : Exactly one to exactly one
- `||--o|` : Exactly one to zero or one
- `||--o{` : Exactly one to zero or many
- `}o--o{` : Zero or many to zero or many
- `}|--|{` : One or many to one or many
**Reading Relationships:**
- `||` = exactly one
- `o|` = zero or one
- `o{` = zero or many
- `|{` = one or many
---
## Relationship Types Explained
### One-to-One (1:1)
**Use case:** Extension tables, profile data
**Syntax:** `||--||`
```mermaid
erDiagram
USER {
uuid id PK
string email
}
USER_PROFILE {
uuid id PK
uuid user_id FK
string bio
string avatar_url
}
USER ||--|| USER_PROFILE : "has"
```
**When to use:**
- Each user has exactly one profile
- Splitting large tables for performance
- Separating frequently vs rarely accessed data
---
### One-to-Many (1:N)
**Use case:** Most common relationship type
**Syntax:** `||--o{` (one to zero-or-many)
```mermaid
erDiagram
USER {
uuid id PK
string email
}
ORDER {
uuid id PK
uuid user_id FK
decimal total
string status
}
USER ||--o{ ORDER : "places"
```
**Reading:** "One USER places zero or many ORDERS"
**When to use:**
- Parent-child relationships
- Ownership (user owns posts, orders, etc.)
- Hierarchical data
---
### Many-to-Many (N:M)
**Use case:** Multiple associations in both directions
**Syntax:** `}o--o{` (zero-or-many to zero-or-many)
**IMPORTANT:** Requires junction table
```mermaid
erDiagram
USER {
uuid id PK
string email
}
ROLE {
uuid id PK
string name UK
}
USER_ROLE {
uuid user_id FK
uuid role_id FK
}
USER ||--o{ USER_ROLE : "has"
ROLE ||--o{ USER_ROLE : "assigned_to"
USER }o--o{ ROLE : "has_roles"
```
**When to use:**
- Users have multiple roles, roles have multiple users
- Products in multiple categories, categories have multiple products
- Students enrolled in courses, courses have multiple students
**Best Practice:** Always create explicit junction table
---
## Complete Example: E-Commerce System
```mermaid
erDiagram
USER {
uuid id PK
string email UK
string password_hash
string first_name
string last_name
timestamp created_at
timestamp updated_at
boolean is_active
}
ADDRESS {
uuid id PK
uuid user_id FK
string street_line1
string street_line2
string city
string state
string postal_code
string country
boolean is_default
}
ORDER {
uuid id PK
uuid user_id FK
uuid shipping_address_id FK
uuid billing_address_id FK
decimal subtotal
decimal tax
decimal shipping_cost
decimal total
string status
timestamp created_at
timestamp updated_at
}
ORDER_ITEM {
uuid id PK
uuid order_id FK
uuid product_id FK
int quantity
decimal unit_price
decimal total_price
}
PRODUCT {
uuid id PK
string sku UK
string name
text description
decimal price
int stock_quantity
boolean is_active
timestamp created_at
timestamp updated_at
}
CATEGORY {
uuid id PK
string name UK
string slug UK
text description
}
PRODUCT_CATEGORY {
uuid product_id FK
uuid category_id FK
}
PAYMENT {
uuid id PK
uuid order_id FK
decimal amount
string payment_method
string transaction_id UK
string status
timestamp created_at
}
USER ||--o{ ADDRESS : "has"
USER ||--o{ ORDER : "places"
ADDRESS ||--o{ ORDER : "ships_to"
ADDRESS ||--o{ ORDER : "bills_to"
ORDER ||--o{ ORDER_ITEM : "contains"
ORDER ||--o| PAYMENT : "paid_by"
PRODUCT ||--o{ ORDER_ITEM : "ordered_as"
PRODUCT ||--o{ PRODUCT_CATEGORY : "categorized_in"
CATEGORY ||--o{ PRODUCT_CATEGORY : "contains"
PRODUCT }o--o{ CATEGORY : "belongs_to"
```
---
## Advanced Patterns
### Self-Referencing Relationships
**Use case:** Hierarchies (org charts, comment threads)
```mermaid
erDiagram
COMMENT {
uuid id PK
uuid parent_comment_id FK
uuid user_id FK
text content
timestamp created_at
}
COMMENT ||--o{ COMMENT : "replies_to"
```
**Reading:** "A COMMENT can have zero or many child COMMENTS"
---
### Polymorphic Relationships
**Use case:** Comments on multiple entity types
**Approach 1: Separate junction tables (recommended)**
```mermaid
erDiagram
COMMENT {
uuid id PK
uuid user_id FK
text content
timestamp created_at
}
POST {
uuid id PK
string title
}
VIDEO {
uuid id PK
string title
}
POST_COMMENT {
uuid post_id FK
uuid comment_id FK
}
VIDEO_COMMENT {
uuid video_id FK
uuid comment_id FK
}
POST ||--o{ POST_COMMENT : "has"
COMMENT ||--o{ POST_COMMENT : "on"
VIDEO ||--o{ VIDEO_COMMENT : "has"
COMMENT ||--o{ VIDEO_COMMENT : "on"
```
**Approach 2: Type discriminator (not recommended)**
```mermaid
erDiagram
COMMENT {
uuid id PK
uuid user_id FK
uuid commentable_id FK
string commentable_type
text content
timestamp created_at
}
```
**Problem:** Can't use foreign key constraints, breaks referential integrity.
---
## Naming Conventions
### Entity Names
- **Use:** UPPERCASE, singular nouns
- **Examples:** USER, ORDER, PRODUCT, PAYMENT
- **Avoid:** USERS (plural), user (lowercase), Usr (abbreviation)
### Field Names
- **Use:** snake_case
- **Examples:** user_id, created_at, email_verified, password_hash
- **Avoid:** userId (camelCase), USERID (uppercase), usrID (abbreviation)
### Relationship Labels
- **Use:** Verb phrases describing the relationship
- **Examples:** "places", "has", "belongs_to", "ships_to", "paid_by"
- **Avoid:** Vague labels like "related", "associated", "linked"
---
## Common Patterns
### Timestamps (Audit Fields)
**Always include:**
```
timestamp created_at
timestamp updated_at
```
**Optional (for soft deletes):**
```
timestamp deleted_at
```
---
### Soft Deletes
```mermaid
erDiagram
USER {
uuid id PK
string email UK
boolean is_deleted
timestamp deleted_at
timestamp created_at
timestamp updated_at
}
```
**When to use:**
- Regulatory requirements (data retention)
- Audit trails needed
- Undelete functionality required
---
### Versioning
```mermaid
erDiagram
DOCUMENT {
uuid id PK
string title
int version
timestamp created_at
}
DOCUMENT_VERSION {
uuid id PK
uuid document_id FK
int version_number
text content
uuid created_by_user_id FK
timestamp created_at
}
DOCUMENT ||--o{ DOCUMENT_VERSION : "has_versions"
```
---
## Best Practices
### 1. Always Define Primary Keys
**Good:**
```
USER {
uuid id PK
string email
}
```
**Bad:**
```
USER {
string email
}
```
### 2. Use Meaningful Foreign Key Names
**Good:**
```
ORDER {
uuid id PK
uuid user_id FK
uuid shipping_address_id FK
}
```
**Bad:**
```
ORDER {
uuid id PK
uuid fk1 FK
uuid fk2 FK
}
```
### 3. Include Relationship Labels
**Good:**
```
USER ||--o{ ORDER : "places"
```
**Bad:**
```
USER ||--o{ ORDER : ""
```
### 4. Document Constraints
Use `UK` for unique constraints:
```
USER {
uuid id PK
string email UK
}
```
### 5. Be Explicit About Optionality
- Use `||--o{` for "zero or many" (optional)
- Use `||--|{` for "one or many" (required)
---
## Common Mistakes
### Mistake 1: Forgetting Junction Tables
❌ **Wrong:**
```mermaid
erDiagram
USER }o--o{ ROLE : "has"
```
✓ **Correct:**
```mermaid
erDiagram
USER {
uuid id PK
}
ROLE {
uuid id PK
}
USER_ROLE {
uuid user_id FK
uuid role_id FK
}
USER ||--o{ USER_ROLE : "has"
ROLE ||--o{ USER_ROLE : "assigned_to"
```
---
### Mistake 2: Wrong Cardinality
❌ **Wrong:** User has exactly one order
```
USER ||--|| ORDER : "places"
```
✓ **Correct:** User has zero or many orders
```
USER ||--o{ ORDER : "places"
```
---
### Mistake 3: Missing Foreign Keys
❌ **Wrong:**
```
ORDER {
uuid id PK
uuid user_id
}
```
✓ **Correct:**
```
ORDER {
uuid id PK
uuid user_id FK
}
```
---
### Mistake 4: Plural Entity Names
❌ **Wrong:**
```
USERS {
uuid id PK
}
```
✓ **Correct:**
```
USER {
uuid id PK
}
```
---
## When to Use ERDs
### Always Use For:
1. **Data model design phase** - Before writing any schema code
2. **Schema migrations** - Visualize changes before implementing
3. **Documentation** - Include in architecture docs, ADRs
4. **Stakeholder communication** - Non-technical reviewers need visuals
### Update ERDs When:
1. Adding new entities
2. Adding/removing relationships
3. Changing cardinality (1:1 → 1:N)
4. Adding significant fields (foreign keys, unique constraints)
### Don't Bother For:
1. Adding simple fields to existing entities (unless FK)
2. Index-only changes (ERD shows logical schema, not physical)
3. Minor data type changes
---
## Integration with Data Model Design Process
### Step 1: Discovery (use data-model-discovery skill)
Ask questions about entities, relationships, query patterns.
### Step 2: ERD Creation (this skill)
Create visual diagram of entities and relationships.
### Step 3: Schema Definition
Translate ERD to SQL/ORM schema:
```sql
CREATE TABLE users (
id UUID PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE TABLE orders (
id UUID PRIMARY KEY,
user_id UUID NOT NULL REFERENCES users(id),
total DECIMAL(10, 2) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
```
### Step 4: Review
Validate ERD against:
- Normalization rules (3NF typically)
- Query patterns (denormalize if needed)
- Performance requirements (indexes)
---
## Tools & Rendering
### Rendering Options
1. **Mermaid Live Editor** - https://mermaid.live
2. **GitHub/GitLab** - Auto-renders in markdown
3. **VS Code** - Mermaid preview extensions
4. **Documentation sites** - Sphinx, MkDocs with mermaid plugin
### Example Markdown Integration
````markdown
# Database Schema
Our e-commerce system uses the following schema:
```mermaid
erDiagram
USER ||--o{ ORDER : "places"
ORDER ||--o{ ORDER_ITEM : "contains"
```
````
---
## Output Checklist
Before finalizing an ERD:
- [ ] All entities in UPPERCASE
- [ ] All fields in snake_case
- [ ] Primary keys marked with PK
- [ ] Foreign keys marked with FK
- [ ] Unique constraints marked with UK
- [ ] Relationships have cardinality symbols
- [ ] Relationships have descriptive labels
- [ ] Junction tables for many-to-many relationships
- [ ] Timestamps (created_at, updated_at) on all entities
- [ ] No plural entity names
- [ ] Diagram renders correctly in Mermaid Live Editor
---
## Summary
**Key Principles:**
1. Entities = UPPERCASE singular nouns
2. Fields = snake_case with type and constraints
3. Relationships = correct cardinality + descriptive label
4. Many-to-many = always use junction table
5. ERDs are living documents - update with schema changes