Skip to main content

How to Create ER Diagrams in Confluence (Mermaid erDiagram Examples)

· 20 min read
NGPilot
NGPilot

Entity-Relationship (ER) diagrams are the standard way to visualize database schemas. They show the tables in your database, the columns in each table, primary and foreign key constraints, and the relationships between tables -- one-to-one, one-to-many, and many-to-many. Whether you are designing a new database from scratch, documenting an existing schema for onboarding, or collaborating on a data model before writing migration scripts, an ER diagram communicates structure faster than any amount of prose.

If your team uses Confluence for technical documentation, embedding ER diagrams directly on your pages keeps your data model documentation next to your architecture decision records, API specs, and sprint planning notes. With Mermaid Plus for Confluence, you can write ER diagrams in plain text using the erDiagram syntax and render them instantly -- no external drawing tool, no exported PNGs, no stale images.

This guide walks you through the full Mermaid erDiagram syntax, explains every relationship type and key constraint, and provides three copy-paste examples you can drop straight into a Confluence page.

Why Create ER Diagrams in Confluence?

Teams that embed database diagrams inside Confluence instead of linking to external tools see several concrete benefits:

Diagrams stay synchronized with documentation. When your ER diagram lives on the same page as the data dictionary, migration plan, and API contract, all of these artifacts evolve together. Edit the diagram, publish the page, and every stakeholder sees the latest schema.

No stale images. Exporting a PNG from a database design tool and attaching it to Confluence guarantees that the image drifts out of date the next time someone runs a migration. A Mermaid macro always renders the current code. If someone changes the schema, they change the Mermaid source on the page.

Text-based and searchable. Mermaid ER diagrams are plain text, which means they integrate with Confluence page history, diffs, and full-text search. You can find every page that references the orders table by searching Confluence -- even if the table name only appears inside a Mermaid macro.

Fast to create and iterate. Typing CUSTOMER ||--o{ ORDER : places is faster than dragging table shapes, drawing relationship lines, and adjusting layout in a visual editor. When you want to add a column, you type it. When you want to change a cardinality, you change one character.

Step-by-Step Tutorial: Create Your First ER Diagram

Follow these five steps to go from a blank Confluence page to a fully rendered database schema diagram.

Step 1 -- Install Mermaid Plus for Confluence

Head to the Atlassian Marketplace and search for Mermaid Plus for Confluence. Click Get App and follow the installation prompts. The app supports both Confluence Cloud and Confluence Data Center. If your organization requires admin approval for marketplace apps, send the link to your Confluence administrator.

Once installed, the Mermaid Plus macro becomes available on every space in your Confluence instance. No per-space configuration required.

Step 2 -- Insert the Mermaid Macro on a Confluence Page

Open any Confluence page in edit mode. Type /mermaid in the editor and select Mermaid Plus for Confluence from the dropdown. The configuration panel opens with a three-column layout:

  • Left column: Live Preview, which renders your diagram in real time as you type
  • Middle column: Quick Templates for all 26 supported diagram types, including ER diagrams
  • Right column: Settings (font, colors, theme, output size) and the Code Editor

You can also click the ER Diagram template in the Quick Templates column to load a starter example into the editor.

Step 3 -- Write the erDiagram Header and Define Entities

Start your ER diagram with the erDiagram keyword. Then define entities and their attributes. Each attribute can have a key type and a comment:

erDiagram
CUSTOMER {
int id PK
string email UK
string name
date created_at
}

The key types are PK (primary key), FK (foreign key), and UK (unique key). You will learn more about key types later in this guide.

Step 4 -- Add Relationships Between Entities

Mermaid supports the full set of ER cardinality operators. To connect two entities, use a relationship line between them:

erDiagram
CUSTOMER ||--o{ ORDER : places

The ||--o{ operator creates a one-to-many relationship: one customer places zero or more orders. You will find a complete reference table for all cardinality operators in the next section.

Step 5 -- Save and Publish the Diagram

Check the live preview in the left column to verify the diagram renders correctly. Adjust the theme, colors, or output size in the right column if needed. When you are satisfied, click Save to insert the macro into the page, then Publish the Confluence page.

To edit the diagram later, click on the rendered diagram in view mode and select Edit. All your code and settings are preserved.

For a complete walkthrough of the configuration panel, themes, font families, color customization, and all 26 supported diagram types, see the Mermaid Plus for Confluence usage guide.

Mermaid ER Diagram Syntax Reference

Before diving into the full examples, here is a quick-reference for the syntax elements you will use most often.

Entity Definitions

An entity represents a table in your database. Define an entity by writing its name in uppercase (by convention) followed by a block of attributes in curly braces:

erDiagram
PRODUCT {
int id PK
string name
string description
decimal price
int stock_quantity
int category_id FK
}

Each attribute line follows this format:

type name [key_type] ["comment"]
  • type: The data type (e.g., int, string, decimal, date, boolean, uuid, text, timestamp)
  • name: The column name
  • key_type (optional): PK for primary key, FK for foreign key, UK for unique key
  • comment (optional): A quoted description of the column

Key Types

Key types mark special constraints on columns. Mermaid renders them with distinct visual indicators:

Key TypeSyntaxDescription
Primary Keyint id PKUniquely identifies each row. Only one per entity.
Foreign Keyint user_id FKReferences a primary key in another entity.
Unique Keystring email UKEnforces uniqueness but is not the primary identifier.

You can combine key types on the same column in some database designs, but Mermaid assigns one visual indicator per attribute line. For composite keys, mark each participating column separately.

Example with all three key types:

erDiagram
USER {
int id PK
string email UK
string username UK
string password_hash
int organization_id FK
timestamp created_at
}

Relationship Cardinality

Relationships are the core of any ER diagram. Mermaid uses a specific notation to express cardinality between two entities. The syntax consists of three parts: the left cardinality, the relationship line, and the right cardinality.

Cardinality Symbols

SymbolMeaning
`
`o`
`}`
o{Zero or more (optional, may be none)

Common Relationship Patterns

RelationshipSyntaxMeaning
One-to-one (mandatory)||--||Each A has exactly one B, and each B has exactly one A
One-to-one (optional)||--o|Each A has zero or one B
One-to-many||--o{One A has zero or more B's
One-to-many (mandatory)||--|{One A has one or more B's
Many-to-one}o--||Many A's relate to one B
Many-to-many}o--o{Many A's relate to many B's

You can add a label to any relationship by appending a colon and text after the second entity:

CUSTOMER ||--o{ ORDER : places
PRODUCT ||--o{ ORDER_ITEM : "included in"

Full Cardinality Reference

Here is every possible combination. The first character pair describes the left entity's cardinality, and the last pair describes the right entity's cardinality:

LeftLineRightExample
||--||One to one (both mandatory)
||--o|One to zero-or-one
||--|{One to one-or-many
||--o{One to zero-or-many
o|--||Zero-or-one to one
o|--o|Zero-or-one to zero-or-one
o|--|{Zero-or-one to one-or-many
o|--o{Zero-or-one to zero-or-many
|{--||One-or-many to one
|{--o|One-or-many to zero-or-one
|{--|{One-or-many to one-or-many
|{--o{One-or-many to zero-or-many
o{--||Zero-or-many to one
o{--o|Zero-or-many to zero-or-one
o{--|{Zero-or-many to one-or-many
o{--o{Zero-or-many to zero-or-many

In practice, you will use ||--o{ (one-to-many) and ||--|| (one-to-one) most frequently. Many-to-many relationships (}o--o{) are typically resolved into a junction table in a normalized database schema.

Attribute Data Types

Mermaid supports a wide range of data types for ER diagram attributes. While these are not enforced by the diagram itself, they serve as documentation for your team:

TypeUsage
intInteger numbers
bigintLarge integers
floatFloating-point numbers
decimalFixed-precision numbers (prices, amounts)
booleanTrue/false values
stringShort text (VARCHAR)
textLong text (TEXT, CLOB)
dateDate without time
timestampDate and time
uuidUniversally unique identifier
jsonJSON data
blobBinary data

Entity Name Conventions

Mermaid ER diagrams use uppercase entity names by convention (e.g., CUSTOMER, ORDER, LINE_ITEM). This distinguishes entities from attributes and relationship labels. Use underscores for multi-word entity names since Mermaid does not support spaces in entity names:

LINE_ITEM
ORDER_STATUS
USER_SESSION

Relationship labels use lowercase with spaces, written after a colon:

CUSTOMER ||--o{ ORDER : places

3 Copy-Paste ER Diagram Examples

Below are three practical examples you can paste directly into the Mermaid Plus macro in Confluence. Each example demonstrates progressively more advanced Mermaid ER diagram features.

Example 1 -- Basic ER Diagram: Library Management System

This example shows a simple library system with books, authors, members, and loans. It covers all three relationship types: one-to-one, one-to-many, and many-to-many. This is a good starting point for documenting any straightforward database schema.

erDiagram
AUTHOR {
int id PK
string name
string nationality
date birth_date
}

BOOK {
int id PK
string title
string isbn UK
int publication_year
int author_id FK
int genre_id FK
}

GENRE {
int id PK
string name UK
string description
}

MEMBER {
int id PK
string email UK
string first_name
string last_name
string phone
date membership_date
}

LOAN {
int id PK
int book_id FK
int member_id FK
date checkout_date
date due_date
date return_date
}

AUTHOR ||--o{ BOOK : writes
GENRE ||--o{ BOOK : categorizes
MEMBER ||--o{ LOAN : borrows
BOOK ||--o{ LOAN : "is borrowed"

This diagram covers three key concepts:

  1. One-to-many relationships -- Each author writes zero or more books (AUTHOR ||--o{ BOOK), each genre categorizes zero or more books, and each member has zero or more loans
  2. Primary and foreign keys -- Every entity has a PK column, and relationship tables like LOAN have FK columns referencing BOOK and MEMBER
  3. Unique constraints -- isbn on BOOK and email on MEMBER are marked UK to indicate uniqueness

Example 2 -- E-Commerce Database Schema

This example models a realistic e-commerce database with customers, products, orders, payments, and shipping. It demonstrates how to handle many-to-many relationships through junction tables, composite foreign keys, and a variety of cardinality patterns. This is the kind of diagram you would include in a technical design document or database migration plan.

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

ADDRESS {
int id PK
int customer_id FK
string street_line_1
string street_line_2
string city
string state
string postal_code
string country
boolean is_default
}

PRODUCT {
int id PK
string name
string description
decimal price
int stock_quantity
string sku UK
int category_id FK
timestamp created_at
timestamp updated_at
}

CATEGORY {
int id PK
string name UK
string slug UK
int parent_category_id FK
string description
}

PRODUCT_TAG {
int id PK
string name UK
}

PRODUCT_TAG_MAP {
int product_id FK
int tag_id FK
}

ORDER {
int id PK
int customer_id FK
string status
decimal subtotal
decimal tax_amount
decimal shipping_cost
decimal total_amount
string shipping_address_snapshot
timestamp created_at
timestamp updated_at
}

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

PAYMENT {
int id PK
int order_id FK
string payment_method
string transaction_id UK
decimal amount
string status
timestamp paid_at
}

SHIPMENT {
int id PK
int order_id FK
string carrier
string tracking_number UK
string status
timestamp shipped_at
timestamp estimated_delivery
timestamp delivered_at
}

REVIEW {
int id PK
int product_id FK
int customer_id FK
int rating
string title
string body
timestamp created_at
}

WISHLIST {
int id PK
int customer_id FK
int product_id FK
timestamp added_at
}

CUSTOMER ||--o{ ADDRESS : has
CUSTOMER ||--o{ ORDER : places
CUSTOMER ||--o{ REVIEW : writes
CUSTOMER ||--o{ WISHLIST : "adds to"
CATEGORY ||--o{ CATEGORY : "sub-category of"
CATEGORY ||--o{ PRODUCT : contains
PRODUCT ||--o{ ORDER_ITEM : "included in"
PRODUCT ||--o{ REVIEW : "receives"
PRODUCT ||--o{ PRODUCT_TAG_MAP : tagged
PRODUCT_TAG ||--o{ PRODUCT_TAG_MAP : applied
ORDER ||--|{ ORDER_ITEM : contains
ORDER ||--o| PAYMENT : "paid by"
ORDER ||--o| SHIPMENT : "shipped via"

This diagram introduces several advanced features:

  1. Self-referencing relationship -- CATEGORY ||--o{ CATEGORY models a hierarchical category tree where a category can have sub-categories
  2. Many-to-many via junction table -- PRODUCT_TAG_MAP resolves the many-to-many relationship between PRODUCT and PRODUCT_TAG
  3. Mandatory one-to-many -- ORDER ||--|{ ORDER_ITEM uses |{ to indicate that every order must have at least one item
  4. Optional one-to-one -- ORDER ||--o| PAYMENT uses o| to indicate that an order may or may not have a payment record (e.g., pending orders)
  5. Unique constraints on transactional data -- transaction_id on PAYMENT and tracking_number on SHIPMENT are marked UK
  6. Snapshot fields -- shipping_address_snapshot on ORDER demonstrates denormalization for audit purposes

Example 3 -- SaaS Multi-Tenant Database Schema

This example models a multi-tenant SaaS application with organizations, users, roles, permissions, projects, and audit logs. It is the most complex of the three examples and demonstrates how to model row-level security patterns, polymorphic associations, and tenant isolation in a database schema. Use this diagram as a starting point when designing any B2B SaaS data model.

erDiagram
ORGANIZATION {
int id PK
string name
string slug UK
string plan
int max_users
boolean is_active
timestamp trial_ends_at
timestamp created_at
}

USER {
int id PK
int organization_id FK
string email UK
string password_hash
string first_name
string last_name
string avatar_url
boolean is_active
timestamp last_login_at
timestamp created_at
}

ROLE {
int id PK
int organization_id FK
string name
string description
boolean is_system
}

PERMISSION {
int id PK
string name UK
string resource
string action
string description
}

USER_ROLE {
int user_id FK
int role_id FK
timestamp assigned_at
}

ROLE_PERMISSION {
int role_id FK
int permission_id FK
}

PROJECT {
int id PK
int organization_id FK
string name
string key UK
string description
string status
int owner_id FK
timestamp created_at
timestamp updated_at
}

PROJECT_MEMBER {
int id PK
int project_id FK
int user_id FK
string role
timestamp joined_at
}

TASK {
int id PK
int project_id FK
int assignee_id FK
int reporter_id FK
string title
string description
string status
string priority
string task_type
int parent_task_id FK
timestamp due_date
timestamp created_at
timestamp updated_at
}

TASK_COMMENT {
int id PK
int task_id FK
int author_id FK
text body
timestamp created_at
timestamp updated_at
}

TASK_ATTACHMENT {
int id PK
int task_id FK
int uploaded_by FK
string file_name
string file_url
int file_size
string mime_type
timestamp uploaded_at
}

AUDIT_LOG {
int id PK
int organization_id FK
int actor_id FK
string action
string resource_type
int resource_id
json changes
string ip_address
timestamp performed_at
}

API_KEY {
int id PK
int organization_id FK
int created_by FK
string name
string key_hash UK
string prefix
string[] scopes
timestamp expires_at
timestamp created_at
}

ORGANIZATION ||--|{ USER : employs
ORGANIZATION ||--o{ ROLE : defines
ORGANIZATION ||--o{ PROJECT : owns
ORGANIZATION ||--o{ AUDIT_LOG : "logs for"
ORGANIZATION ||--o{ API_KEY : "issues"
USER ||--o{ USER_ROLE : has
ROLE ||--o{ USER_ROLE : assigned
ROLE ||--o{ ROLE_PERMISSION : grants
PERMISSION ||--o{ ROLE_PERMISSION : "included in"
PROJECT ||--o{ PROJECT_MEMBER : "has members"
USER ||--o{ PROJECT_MEMBER : "joins"
PROJECT ||--|{ TASK : contains
USER ||--o{ TASK : assigned
USER ||--o{ TASK : reported
TASK ||--o{ TASK : "sub-task of"
TASK ||--o{ TASK_COMMENT : has
TASK ||--o{ TASK_ATTACHMENT : has
USER ||--o{ TASK_COMMENT : authors
USER ||--o{ TASK_ATTACHMENT : uploads
USER ||--o{ AUDIT_LOG : performs
USER ||--o{ API_KEY : creates

This diagram demonstrates every major Mermaid ER diagram feature in a production-ready context:

  1. Multi-tenant isolation -- Every top-level entity has an organization_id FK column, enforcing tenant boundaries at the data layer
  2. Role-based access control (RBAC) -- The USER_ROLE, ROLE, ROLE_PERMISSION, and PERMISSION entities form a complete RBAC model with many-to-many relationships resolved through junction tables
  3. Self-referencing hierarchy -- TASK ||--o{ TASK allows tasks to have sub-tasks, modeling an unlimited nesting depth
  4. Multiple foreign keys to the same table -- TASK has both assignee_id FK and reporter_id FK pointing to USER, with corresponding relationship lines
  5. Polymorphic audit trail -- AUDIT_LOG uses resource_type and resource_id to track changes across any entity type, with a json column for change details
  6. API key management -- API_KEY stores hashed keys with scope arrays and expiration, scoped to organizations
  7. Mandatory vs optional cardinality -- ORGANIZATION ||--|{ USER (every org has at least one user) vs ORGANIZATION ||--o{ API_KEY (API keys are optional)

Tips for Building Effective ER Diagrams

Normalize Before Diagramming

Before writing a single line of Mermaid, make sure your schema follows at least third normal form (3NF). Each entity should represent one concept, each attribute should depend on the whole primary key, and there should be no transitive dependencies. ER diagrams are most useful when the underlying model is clean.

Start with Entities, Then Add Relationships

Begin by listing all your entities and their attributes. Get the column names and key types right first. Then add relationship lines between entities. This two-pass approach prevents you from getting lost in cardinality notation before the entities themselves are well-defined.

Use Junction Tables for Many-to-Many

Many-to-many relationships (}o--o{) are valid in Mermaid syntax, but in a relational database you always resolve them through a junction table. Instead of drawing a direct many-to-many line, create an intermediate entity with two foreign keys:

-- Instead of this:
PRODUCT }o--o{ TAG : "tagged with"

-- Do this:
PRODUCT ||--o{ PRODUCT_TAG_MAP : tagged
TAG ||--o{ PRODUCT_TAG_MAP : applied

This matches how the database actually implements the relationship and makes the diagram more useful as a reference for writing SQL.

Label Every Relationship

Add descriptive labels to your relationship lines. CUSTOMER ||--o{ ORDER : places is clearer than CUSTOMER ||--o{ ORDER. The label tells the reader what the relationship means in business terms, not just that a foreign key exists.

Keep Diagrams Focused

A single ER diagram does not need to show every table in your database. Focus on one subsystem or one feature area per diagram. If you find yourself adding more than 12-15 entities, consider splitting the diagram into multiple pages and linking between them. Two focused diagrams are always better than one overwhelming diagram.

Be Consistent with Naming Conventions

Pick a naming convention and stick to it throughout the diagram. Common conventions include:

  • Entity names: UPPER_SNAKE_CASE (e.g., ORDER_ITEM, USER_SESSION)
  • Attribute names: snake_case (e.g., created_at, user_id)
  • Primary keys: Always named id or {entity_name}_id
  • Foreign keys: Always named {referenced_entity}_id (e.g., customer_id, order_id)

Consistent naming makes the diagram self-documenting and reduces the cognitive load on readers.

Use Themes for Visual Consistency

Mermaid Plus for Confluence offers four built-in themes: Default, Dark, Forest, and Neutral. Pick one theme for all ER diagrams in a space and stick with it. The Default theme lets you customize node, text, border, line, and background colors to match your company brand. Consistent visual style across pages makes your documentation feel polished and professional.

For detailed configuration options including font families, color pickers, and output sizes, refer to the Mermaid Plus for Confluence usage guide.

Common Mistakes and How to Fix Them

Missing erDiagram header. Every ER diagram must start with the erDiagram keyword on its own line. Writing entity definitions without this header produces a parse error. The correct form is:

erDiagram
CUSTOMER ||--o{ ORDER : places

Wrong cardinality direction. The cardinality symbols closest to an entity describe that entity's role. In CUSTOMER ||--o{ ORDER : places, the || is next to CUSTOMER (exactly one customer) and o{ is next to ORDER (zero or more orders). If your diagram looks reversed, swap the sides of the relationship line.

Spaces in entity names. Mermaid does not support spaces in entity names. Use underscores instead: ORDER_ITEM, not ORDER ITEM. Relationship labels can contain spaces because they are written after the colon.

Missing foreign key annotations. If a column references another table's primary key, mark it with FK. This makes the relationship visually explicit in the diagram and helps readers trace referential integrity without hunting through relationship lines.

Overcrowding. An ER diagram with 20 entities and 40 relationships becomes unreadable. If your diagram has grown too large, split it by domain, subsystem, or feature area. Link the pages together so readers can navigate between focused views.

Forgetting to close attribute blocks. Every { must have a matching }. If your diagram fails to render, check that every entity's attribute block is properly closed. The live preview in Mermaid Plus will show you parse errors in real time, which makes this easy to catch.

ER Diagrams vs Class Diagrams vs Flowcharts

ER diagrams are not the right tool for every situation. Here is a quick guide to help you choose the right diagram type:

  • ER diagram -- Use when documenting relational database schemas, data models, and table relationships. ER diagrams focus on tables, columns, key constraints, and cardinality.
  • Class diagram -- Use when documenting object-oriented systems, domain models, and API contracts with methods, visibility, and inheritance. See how to create class diagrams in Confluence.
  • Flowchart -- Use when documenting processes, decision trees, approval workflows, and algorithmic logic. See how to create flowcharts in Confluence.

Many technical design documents benefit from combining multiple diagram types on the same Confluence page. An ER diagram shows the data model, a class diagram shows the application layer, and a flowchart shows the business process that ties them together.

Mermaid Syntax Cheat Sheet

For a quick reference covering ER diagrams and all other Mermaid diagram types supported in Confluence, bookmark the Mermaid syntax cheat sheet for Confluence. It covers flowcharts, sequence diagrams, class diagrams, ER diagrams, Gantt charts, and more in a single-page reference.

ER diagrams are one of the most valuable tools in a software team's documentation toolkit. They capture the data model of your system in a way that prose alone cannot match. With Mermaid Plus for Confluence, creating and maintaining ER diagrams is as simple as writing text. Install the app, paste one of the examples above into a Confluence page, and start documenting your database schema where it belongs -- alongside everything else your team needs.