Tools mentioned in this article
Open the browser-based tool while you read and try the workflow immediately.
ER 다이어그램, 이제 “그리지” 말고 “쓰세요”
그래픽 도구로 ER(개체-관계) 다이어그램을 그리면, 테이블이 하나 늘 때마다 선을 다시 연결해야 하고 결국 그림이 실제 스키마와 어긋나게 됩니다. **Mermaid의 erDiagram**을 쓰면 다이어그램이 평범한 텍스트가 됩니다. 저장소 안에 함께 있고, diff에도 나타나며, GitHub README·PR·Notion을 비롯한 대부분의 Markdown 뷰어에서 자동으로 렌더링됩니다.
이 글은 훑어보며 바로 참고할 수 있는 레퍼런스입니다. 카디널리티 치트시트, 속성 문법, 완전한 실전 예제, 그리고 마지막으로 기존 SQL에서 이 모든 걸 자동 생성하는 방법까지 다룹니다.
최소 예제: 세 줄로 시작하기
erDiagram
USERS ||--o{ POSTS : "has"
이것만으로 “USERS와 POSTS는 1대다(한 사용자가 0개 이상의 게시글을 가짐)“가 렌더링됩니다. 일반 형식은 다음과 같습니다.
<엔티티1> <왼쪽 카디널리티><선><오른쪽 카디널리티> <엔티티2> : "라벨"
미리 알아둘 점 하나: 콜론 뒤의 관계 라벨은 필수입니다. 텍스트를 보이고 싶지 않다면 : ""로 쓰세요. 아예 생략하면 문법 오류가 나며, 이것이 가장 흔한 첫 번째 실수입니다.
카디널리티 기호: 치트시트
erDiagram의 카디널리티는 까마귀발(crow’s foot) 표기법을 따릅니다. 기호는 항상 해당 엔티티 쪽을 향합니다.
| 왼쪽 기호 | 오른쪽 기호 | 의미 |
|---|---|---|
|o | o| | 0 또는 1 |
|| | || | 정확히 1 |
}o | o{ | 0개 이상 |
}| | |{ | 1개 이상 |
구체적인 조합으로 외우는 게 가장 빠릅니다.
| 문법 | 의미 |
|---|---|
A ||--o{ B | A는 1, B는 0개 이상 (가장 흔한 1대다) |
A ||--|{ B | A는 1, B는 반드시 1개 이상 |
A |o--o| B | 선택적 1대1 |
A ||--|| B | 엄격한 1대1 |
A }o--o{ B | 다대다 (중간 테이블을 넣기 전의 개념적 표현) |
실선 vs 점선: 식별 관계 vs 비식별 관계
선 부분은 두 종류가 있습니다.
| 선 | 의미 | 주로 쓰이는 곳 |
|---|---|---|
-- | 식별 관계 (실선) | 자식의 기본키가 부모의 PK를 포함 (예: 주문 상세 항목) |
.. | 비식별 관계 (점선) | 자식이 일반 FK로 부모를 참조 (예: 게시글과 작성자) |
ORDERS ||--|{ ORDER_ITEMS : "contains" %% 식별 관계(실선)
USERS ||..o{ POSTS : "writes" %% 비식별 관계(점선)
%%는 주석입니다. 식별 관계를 구분해서 쓸지, 아니면 실선으로 통일할지는 팀에서 정하세요. 둘 다 괜찮지만, 일관성이 있어야 다이어그램을 읽기 편합니다.
속성(컬럼) 정의하기
엔티티에 {} 블록을 붙이면 컬럼을 표 형태로 렌더링할 수 있습니다.
erDiagram
USERS {
int id PK "자동 증가"
varchar(255) email UK "로그인 ID"
varchar(100) name
datetime created_at
}
각 줄은 타입 이름 [키] ["주석"] 형식입니다.
- 키는
PK/FK/UK이며, 쉼표로 구분해 여러 개를 조합할 수 있습니다(PK, FK) — 복합키를 가진 중간 테이블에 필수 - 타입에 괄호를 포함할 수 있습니다.
varchar(255)나decimal(10)처럼요 - 주석은 큰따옴표로 감쌉니다
실전 예제: 전자상거래 주문
지금까지 배운 문법을 전부 담은, 그대로 복사해서 쓸 수 있는 다이어그램입니다.
erDiagram
USERS ||--o{ ORDERS : "places"
ORDERS ||--|{ ORDER_ITEMS : "contains"
PRODUCTS ||--o{ ORDER_ITEMS : "included in"
USERS {
int id PK
varchar(255) email UK
varchar(100) name
datetime created_at
}
ORDERS {
int id PK
int user_id FK
varchar(20) status
datetime ordered_at
}
ORDER_ITEMS {
int order_id PK, FK
int product_id PK, FK
int quantity
decimal(10) unit_price
}
PRODUCTS {
int id PK
varchar(200) name
decimal(10) price
}
핵심은 ORDER_ITEMS입니다. 주문과 상품 사이의 다대다 관계를, 복합 기본키(두 개의 PK, FK 컬럼)를 가진 중간 테이블로 풀어냈고, “주문에는 반드시 상세 항목이 1개 이상 있다”는 비즈니스 규칙을 ||--|{ 카디널리티로 표현했습니다.
흔한 함정과 피하는 법
- 관계 라벨은 필수입니다. 숨기고 싶으면
: "" - 엔티티 이름은 영문(ASCII)을 권장합니다. 비ASCII 이름의 렌더링은 환경마다 달라질 수 있으므로, 테이블 이름은 영어로 두고 현지어는 라벨이나 주석에 넣으세요
- 다대다(
}o--o{)는 개념 단계에서만 사용하세요. 구현 전에 중간 테이블로 풀어야 합니다 - GitHub에서 렌더링이 안 되나요? 코드 블록 언어가 정확히
```mermaid인지 확인하세요
CREATE TABLE 문에서 자동 생성하기
테이블이 10개를 넘어가면 이 문법을 손으로 쓰는 게 지루해집니다. 이미 DDL이 있다면 **SQL to ER 다이어그램 변환 도구**에 붙여넣기만 하세요 — 기본키, 외래키, 관계를 분석해서 Mermaid ER 다이어그램을 자동으로 생성합니다.

모든 처리가 브라우저 안에서만 이루어지므로, 민감한 스키마 정보가 외부로 전송되지 않습니다. 기본 다이어그램을 생성한 뒤 위의 치트시트를 참고해 다듬으세요. 도구 자체에 대한 자세한 설명은 SQL DDL에서 ER 다이어그램 생성하는 방법을 참고하세요.
자주 묻는 질문
1대다 관계는 어떻게 쓰는 게 맞나요?
부모 ||--o{ 자식이 기본형입니다(부모 1개, 자식 0개 이상). “자식이 반드시 1개 이상 있어야 한다”가 실제 비즈니스 규칙일 때만 ||--|{를 쓰세요. 헷갈리면 ||--o{가 안전한 기본값입니다.
속성을 정의하지 않고 관계만 그릴 수 있나요?
네. {} 블록이 없어도 관계 라인에 등장한 엔티티는 렌더링됩니다. 설계 초기에는 관계만 그리고, 스키마가 안정된 뒤 속성 블록을 추가하는 방식이 실무에서 유용합니다.
Mermaid ER 다이어그램은 어디서 렌더링할 수 있나요?
GitHub(README, 이슈, PR), GitLab, Notion, VS Code(확장 기능 사용 시), Obsidian 등 대부분의 최신 Markdown 환경이 Mermaid 코드 블록을 기본으로 렌더링합니다. 그 외 환경에서는 Mermaid Live Editor로 SVG/PNG를 내보낼 수 있습니다.
다대다 관계를 그대로 구현할 수 있나요?
아니요. A }o--o{ B는 개념적 표기일 뿐입니다. 관계형 데이터베이스에서는 위 전자상거래 예제처럼 중간 테이블(복합 기본키 + 외래키 2개)이 필요합니다. 처음부터 다이어그램에 해소된 형태로 그려두면 구현 단계에서 재작업을 줄일 수 있습니다.