Excalidraw Diagram Design Guide
Color Palette
Stroke Colors (borders & text)
| Name |
Hex |
Use for |
| Black |
#1e1e1e |
Default text & borders |
| Red |
#e03131 |
Errors, warnings, critical |
| Green |
#2f9e44 |
Success, approved, healthy |
| Blue |
#1971c2 |
Primary actions, links |
| Purple |
#9c36b5 |
Services, middleware |
| Orange |
#e8590c |
Async, queues, events |
| Cyan |
#0c8599 |
Data stores, databases |
| Gray |
#868e96 |
Annotations, secondary |
Fill Colors (backgroundColor — pastel)
| Name |
Hex |
Pairs with stroke |
| Light Red |
#ffc9c9 |
#e03131 |
| Light Green |
#b2f2bb |
#2f9e44 |
| Light Blue |
#a5d8ff |
#1971c2 |
| Light Purple |
#eebefa |
#9c36b5 |
| Light Orange |
#ffd8a8 |
#e8590c |
| Light Cyan |
#99e9f2 |
#0c8599 |
| Light Gray |
#e9ecef |
#868e96 |
| White |
#ffffff |
#1e1e1e |
Sizing Rules
- Minimum shape: width >= 120px, height >= 60px
- Shape width formula:
max(160, charCount * 11 + 40) — the +40 is mandatory padding, never skip it
- Multi-word labels: measure the longest single word:
max(160, longestWord * 11 + 80)
- Shape height: 60px single-line, 80px two-line, 100px three-line labels
- Font sizes: body text >= 16, titles/headers >= 20, small labels >= 14
- Padding: at least 20px inside shapes for text breathing room
- Arrow gap: minimum 80px between connected shapes — closer = arrows overdraw the border
- Consistent sizing: same-role shapes = same dimensions
Layout Patterns
- Grid snap: align to 20px grid for clean layouts
- Spacing: 40–80px gap between adjacent shapes
- Flow direction: top-to-bottom (vertical) or left-to-right (horizontal)
- Hierarchy: important nodes larger or higher; left-to-right = temporal order
- Grouping: cluster related elements; use background rectangles as zones
- Tier layout:
- Tier 1 (y=50–130): Client apps / entry points - Tier 2 (y=200–280): Gateway / edge layer - Tier 3 (y=350–440): Services (spread wide: 160–200px apart) - Tier 4 (y=510–590): Data stores - Side panels: x < 0 or x > mainDiagramRight + 80
Arrow Best Practices
Binding (always use element IDs, not raw coordinates)
{"type": "arrow", "x": 0, "y": 0, "start": {"id": "svc-a"}, "end": {"id": "svc-b"}}
Server auto-routes arrows to element edges using precise geometry.
Line styles
- Solid: synchronous calls, direct dependencies
- Dashed (
"strokeStyle": "dashed"): async flows, optional paths, events
- Dotted (
"strokeStyle": "dotted"): weak dependencies, annotations
Arrowheads
"endArrowhead": "arrow" — default directed flow
"endArrowhead": "dot" — data stores / database relationships
"endArrowhead": "bar" — cardinality (ER diagrams)
"endArrowhead": "triangle" — filled triangle (UML)
"endArrowhead": null — plain line (undirected)
"startArrowhead" mirrors the same options for bidirectional arrows
Labels on arrows
Use "label": {"text": "HTTP"} — keep to 1–2 words. Long labels overlap shapes.
Routing complex arrows (avoid crossings)
Elbowed arrow (right-angle routing — cleanest for architecture diagrams):
{
"type": "arrow", "x": 0, "y": 0,
"start": {"id": "svc-a"},
"end": {"id": "svc-b"},
"elbowed": true
}
Curved arc (for arrows that need to arc over elements):
{
"type": "arrow", "x": 100, "y": 100,
"points": [[0,0],[50,-40],[200,0]],
"roundness": {"type": 2},
"strokeColor": "#1971c2"
}
Fill Styles (fillStyle)
Controls how shape interiors are rendered. Default is "hachure" (Excalidraw's signature sketchy look).
| Value |
Appearance |
Best for |
"solid" |
Flat solid color |
Clean production diagrams |
"hachure" |
Diagonal hatching (default) |
Sketchy/hand-drawn style |
"cross-hatch" |
Grid hatching |
Emphasis, dense areas |
"dots" |
Dot pattern |
Light texture, secondary elements |
"zigzag" |
Zigzag lines |
Decorative, callouts |
"zigzag-line" |
Single zigzag |
Borders/edges |
Use "solid" for any diagram meant to look professional. Only use "hachure" if you want the hand-drawn aesthetic intentionally.
{"type": "rectangle", "fillStyle": "solid", "backgroundColor": "#a5d8ff", ...}
Rounded Corners (roundness)
Add "roundness": {"type": 3} to rectangle and ellipse elements for rounded corners.
{"type": "rectangle", "roundness": {"type": 3}, ...}
Omit roundness (or set to null) for sharp corners.
Diagram Type Templates
Architecture Diagram
{
"elements": [
{
"id": "zone-backend",
"type": "rectangle",
"x": 40, "y": 40, "width": 600, "height": 400,
"backgroundColor": "#e9ecef", "strokeColor": "#868e96",
"opacity": 40,
"label": {"text": "Backend", "fontSize": 20}
},
{
"id": "api-gw",
"type": "rectangle",
"x": 80, "y": 100, "width": 180, "height": 70,
"strokeColor": "#9c36b5", "backgroundColor": "#eebefa",
"label": {"text": "API Gateway"}
},
{
"id": "auth-svc",
"type": "rectangle",
"x": 80, "y": 240, "width": 180, "height": 70,
"strokeColor": "#1971c2", "backgroundColor": "#a5d8ff",
"label": {"text": "Auth Service"}
},
{
"id": "db",
"type": "rectangle",
"x": 80, "y": 380, "width": 180, "height": 70,
"strokeColor": "#0c8599", "backgroundColor": "#99e9f2",
"label": {"text": "Postgres"}
},
{"type":"arrow","x":0,"y":0,"start":{"id":"api-gw"},"end":{"id":"auth-svc"},"label":{"text":"JWT verify"}},
{"type":"arrow","x":0,"y":0,"start":{"id":"auth-svc"},"end":{"id":"db"},"label":{"text":"SQL"},"strokeStyle":"dashed"}
]
}
Flowchart
{
"elements": [
{"id":"start","type":"ellipse","x":160,"y":40,"width":120,"height":60,
"strokeColor":"#2f9e44","backgroundColor":"#b2f2bb","label":{"text":"Start"}},
{"id":"step1","type":"rectangle","x":140,"y":160,"width":160,"height":60,
"strokeColor":"#1971c2","backgroundColor":"#a5d8ff","label":{"text":"Validate Input"}},
{"id":"decide","type":"diamond","x":140,"y":280,"width":160,"height":80,
"strokeColor":"#e8590c","backgroundColor":"#ffd8a8","label":{"text":"Valid?"}},
{"id":"end-ok","type":"ellipse","x":340,"y":290,"width":100,"height":60,
"strokeColor":"#2f9e44","backgroundColor":"#b2f2bb","label":{"text":"Success"}},
{"id":"end-err","type":"ellipse","x":0,"y":290,"width":100,"height":60,
"strokeColor":"#e03131","backgroundColor":"#ffc9c9","label":{"text":"Error"}},
{"type":"arrow","x":0,"y":0,"start":{"id":"start"},"end":{"id":"step1"}},
{"type":"arrow","x":0,"y":0,"start":{"id":"step1"},"end":{"id":"decide"}},
{"type":"arrow","x":0,"y":0,"start":{"id":"decide"},"end":{"id":"end-ok"},"label":{"text":"Yes"}},
{"type":"arrow","x":0,"y":0,"start":{"id":"decide"},"end":{"id":"end-err"},"label":{"text":"No"}}
]
}
ER Diagram
{
"elements": [
{"id":"users","type":"rectangle","x":40,"y":100,"width":180,"height":120,
"strokeColor":"#1971c2","backgroundColor":"#a5d8ff",
"label":{"text":"users\n─────\nid: UUID\nname: text\nemail: text"}},
{"id":"orders","type":"rectangle","x":300,"y":100,"width":180,"height":120,
"strokeColor":"#9c36b5","backgroundColor":"#eebefa",
"label":{"text":"orders\n──────\nid: UUID\nuser_id: UUID\ntotal: decimal"}},
{"type":"arrow","x":0,"y":0,"start":{"id":"users"},"end":{"id":"orders"},
"label":{"text":"1..N"},"endArrowhead":"arrow","startArrowhead":"dot"}
]
}
Mindmap (Clean Radial, 5 Branches)
Use this when a user asks for a minimal mindmap with directional branches.
Rules:
- Keep one center node and place first-level branches radially around it (not in a loose grid).
- Keep all labels inside shape text; never leave branch words floating outside boxes.
- Use bound arrows with
start/end IDs only.
- Keep branch lengths similar unless direction intentionally emphasizes a topic.
Reference coordinates (centered canvas):
- Center:
(560, 320)
- Branch vectors: up
(0,-180), right (240,-40), down-right (220,190), down-left (-220,190), left (-240,-40)
- Child vectors from each branch: continue same direction by 160-220px.
Coordinate note:
- Element
x/y values are top-left anchors; evaluate radial balance using node centers, not top-left corners.
{
"elements": [
{"id":"center","type":"ellipse","x":560,"y":320,"width":220,"height":100,
"strokeColor":"#374151","backgroundColor":"#f3f4f6","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Focus Topic"}},
{"id":"b1","type":"rectangle","x":560,"y":140,"width":190,"height":60,
"strokeColor":"#1f2937","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Branch 1"}},
{"id":"b2","type":"rectangle","x":800,"y":280,"width":190,"height":60,
"strokeColor":"#1f2937","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Branch 2"}},
{"id":"b3","type":"rectangle","x":780,"y":510,"width":190,"height":60,
"strokeColor":"#1f2937","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Branch 3"}},
{"id":"b4","type":"rectangle","x":340,"y":510,"width":190,"height":60,
"strokeColor":"#1f2937","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Branch 4"}},
{"id":"b5","type":"rectangle","x":320,"y":280,"width":190,"height":60,
"strokeColor":"#1f2937","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Branch 5"}},
{"id":"c1","type":"rectangle","x":560,"y":-30,"width":180,"height":52,
"strokeColor":"#6b7280","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Detail 1"}},
{"id":"c2","type":"rectangle","x":1060,"y":240,"width":180,"height":52,
"strokeColor":"#6b7280","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Detail 2"}},
{"id":"c3","type":"rectangle","x":1030,"y":640,"width":180,"height":52,
"strokeColor":"#6b7280","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Detail 3"}},
{"id":"c4","type":"rectangle","x":100,"y":640,"width":180,"height":52,
"strokeColor":"#6b7280","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Detail 4"}},
{"id":"c5","type":"rectangle","x":40,"y":240,"width":180,"height":52,
"strokeColor":"#6b7280","backgroundColor":"#ffffff","fillStyle":"solid","roundness":{"type":3},
"label":{"text":"Detail 5"}},
{"type":"arrow","x":0,"y":0,"start":{"id":"center"},"end":{"id":"b1"},"strokeColor":"#9ca3af","endArrowhead":"arrow"},
{"type":"arrow","x":0,"y":0,"start":{"id":"center"},"end":{"id":"b2"},"strokeColor":"#9ca3af","endArrowhead":"arrow"},
{"type":"arrow","x":0,"y":0,"start":{"id":"center"},"end":{"id":"b3"},"strokeColor":"#9ca3af","endArrowhead":"arrow"},
{"type":"arrow","x":0,"y":0,"start":{"id":"center"},"end":{"id":"b4"},"strokeColor":"#9ca3af","endArrowhead":"arrow"},
{"type":"arrow","x":0,"y":0,"start":{"id":"center"},"end":{"id":"b5"},"strokeColor":"#9ca3af","endArrowhead":"arrow"},
{"type":"arrow","x":0,"y":0,"start":{"id":"b1"},"end":{"id":"c1"},"strokeColor":"#9ca3af","endArrowhead":"arrow"},
{"type":"arrow","x":0,"y":0,"start":{"id":"b2"},"end":{"id":"c2"},"strokeColor":"#9ca3af","endArrowhead":"arrow"},
{"type":"arrow","x":0,"y":0,"start":{"id":"b3"},"end":{"id":"c3"},"strokeColor":"#9ca3af","endArrowhead":"arrow"},
{"type":"arrow","x":0,"y":0,"start":{"id":"b4"},"end":{"id":"c4"},"strokeColor":"#9ca3af","endArrowhead":"arrow"},
{"type":"arrow","x":0,"y":0,"start":{"id":"b5"},"end":{"id":"c5"},"strokeColor":"#9ca3af","endArrowhead":"arrow"}
]
}
Anti-Patterns to Avoid
- Overlapping elements — always leave gaps; use
excalidraw distribute
- Cramped spacing — minimum 40px between shapes; 60px between diagram tiers
- Tiny fonts — never below 14px; prefer 16+ for readability
- Raw arrow coordinates — always use
start/end binding to connect to shapes
- Too many colors — limit to 3–4 fill colors per diagram
- Inconsistent sizes — same-role shapes should have identical width/height
- No labels — every shape and meaningful arrow needs descriptive text
- Flat layouts — use background zones/groups to show hierarchy
- Side panels overlapping main diagram — place at x < 0 or x > mainRight + 80
- Unchecked arrow crossings — use
"elbowed": true or route with waypoints
- Forgetting
fillStyle: "solid" — default is "hachure" (sketchy); always set "fillStyle": "solid" for clean diagrams
- Mindmap drift — avoid random placement; use radial vectors from center and continue each branch in the same direction
- Detached labels — if text appears outside a node, fix node label and remove loose text elements
Pre-Drawing Checklist
Before writing any JSON: