Skip to content

Sequence diagrams

A sequence diagram shows who calls whom, and in what order: a request path, a protocol, a handshake. Each actor is a column with a lifeline, and time runs down the page. The sequence spec reference lists every field and its allowed values.

basic.json
{
"type": "sequence",
"actors": [
{"id": "client", "label": "Client"},
{"id": "gateway", "label": "API Gateway"},
{"id": "auth", "label": "Auth Service"},
{"id": "queue", "label": "Audit Queue"}
],
"interactions": [
{"from": "client", "to": "gateway", "label": "POST /login", "style": "solid"},
{"from": "gateway", "to": "auth", "label": "validate credentials", "style": "solid"},
{"from": "auth", "to": "auth", "label": "hash password", "style": "solid"},
{"from": "auth", "to": "gateway", "label": "token", "style": "dashed"},
{"from": "gateway", "to": "queue", "label": "log sign-in", "style": "async"},
{"from": "gateway", "to": "client", "label": "200 OK", "style": "dashed"}
]
}
A Client posts a login to an API Gateway, which asks an Auth Service to validate credentials; Auth hashes the password in a self-message and returns a token, the gateway logs the sign-in to an Audit Queue asynchronously, and answers the client 200 OK.A Client posts a login to an API Gateway, which asks an Auth Service to validate credentials; Auth hashes the password in a self-message and returns a token, the gateway logs the sign-in to an Audit Queue asynchronously, and answers the client 200 OK.
  ┌────────┐  ┌──────────────┐        ┌──────────────┐  ┌──────────────┐
  │ Client │  │ API Gateway  │        │ Auth Service │  │ Audit Queue  │
  └────────┘  └──────────────┘        └──────────────┘  └──────────────┘
       │              │                       │                 │
       │              │                       │                 │
       ├ POST /login ─►                       │                 │
       │              ┃                       │                 │
       │              ├ validate credentials ─►                 │
       │              │                       ┃                 │
       │              │                       ┃───┐             │
       │              │                       ┃   │ hash password
       │              │                       ◄───┘             │
       │              │                       ┃                 │
       │              ◄╌╌╌╌╌╌╌╌ token ╌╌╌╌╌╌╌╌┤                 │
       │              ┃                       │                 │
       │              ┠────────────── log sign-in ──────────────▷
       │              ┃                       │                 │
       ◄╌╌ 200 OK ╌╌╌╌┤                       │                 │
       ┃              │                       │                 │
  ┌────────┐  ┌──────────────┐        ┌──────────────┐  ┌──────────────┐
  │ Client │  │ API Gateway  │        │ Auth Service │  │ Audit Queue  │
  └────────┘  └──────────────┘        └──────────────┘  └──────────────┘

Actors are drawn left to right in the order of the actors array. Put the initiator leftmost, then the others in order of first appearance, and name them by role (“Auth Service”), not by technology. A message names its ends by actor id, so give each actor a short id.

Each interaction has a style:

Style Use Arrow
solid a call (the default) a filled arrowhead
dashed a return a dashed line
async fire-and-forget: the sender does not wait an open arrowhead

In the diagram above, POST /login and validate credentials are solid calls, token and 200 OK are dashed returns, and log sign-in to the queue is async. Interactions are drawn in array order, top to bottom. Label messages with what happens, not with data or calls: those raise vague-message-label.

When an actor does something internally, make an interaction with the same from and to. It is drawn as a short loop on that actor’s lifeline: hash password above.

A fragment draws a frame around part of the exchange, with its type in a tab at the top-left corner and each section’s guard in brackets. The types are alt (if and else, one section per branch), opt (may happen), loop (repeats), par (happens in parallel) and break (leaves the sequence). over lists the actors it spans; the frame also widens to every actor its messages reach.

fragments.json
{
"type": "sequence",
"actors": [
{"id": "client", "label": "Client"},
{"id": "api", "label": "API"},
{"id": "db", "label": "Database"}
],
"interactions": [
{"from": "client", "to": "api", "label": "place order", "style": "solid"},
{"from": "api", "to": "db", "label": "check stock", "style": "solid"},
{"from": "db", "to": "api", "label": "in stock", "style": "dashed"},
{"from": "api", "to": "db", "label": "reserve items", "style": "solid"},
{"from": "api", "to": "client", "label": "out of stock", "style": "dashed"},
{"from": "api", "to": "db", "label": "log stock miss", "style": "solid"},
{"from": "api", "to": "client", "label": "send receipt", "style": "dashed"},
{"from": "api", "to": "db", "label": "retry write", "style": "solid"},
{"from": "api", "to": "db", "label": "write audit row", "style": "solid"},
{"from": "api", "to": "client", "label": "payment failed", "style": "dashed"}
],
"fragments": [
{
"type": "alt",
"over": ["client", "api", "db"],
"sections": [
{"label": "in stock", "start": 2, "end": 3},
{"label": "out of stock", "start": 4, "end": 5}
]
},
{
"type": "opt",
"over": ["api", "client"],
"sections": [{"label": "receipt requested", "start": 6, "end": 6}]
},
{
"type": "loop",
"over": ["api", "db"],
"sections": [{"label": "up to 3 times", "start": 7, "end": 7}]
},
{"type": "par", "over": ["api", "db"], "sections": [{"label": "audit", "start": 8, "end": 8}]},
{
"type": "break",
"over": ["api", "client"],
"sections": [{"label": "payment declined", "start": 9, "end": 9}]
}
]
}
An order exchange between Client, API and Database with an alt frame of two sections (in stock, out of stock), then an opt for a receipt, a loop of up to 3 retries, a par for an audit write and a break for a declined payment.An order exchange between Client, API and Database with an alt frame of two sections (in stock, out of stock), then an opt for a receipt, a loop of up to 3 retries, a par for an audit write and a break for a declined payment.
    ┌────────┐         ┌──────┐         ┌──────────┐
    │ Client │         │ API  │         │ Database │
    └────────┘         └──────┘         └──────────┘
         │                 │                  │
         │                 │                  │
         ├── place order ──►                  │
         │                 ┃                  │
         │                 ├── check stock ───►
         │                 │                  ┃
  ╔══ alt [in stock] ══════╪══════════════════╪═════╗
  ║      │                 ◄╌╌╌ in stock ╌╌╌╌╌┤     ║
  ║      │                 ┃                  │     ║
  ║      │                 ├─ reserve items ──►     ║
  ║      │                 │                  ┃     ║
  ╟╌╌ [out of stock] ╌╌╌╌╌╌╪╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╪╌╌╌╌╌╢
  ║      ◄╌ out of stock ╌╌┤                  │     ║
  ║      ┃                 │                  │     ║
  ║      │                 ├ log stock miss ──►     ║
  ╚══════╪═════════════════╪══════════════════╪═════╝
         │                 │                  │
  ╔══ opt [receipt requested] ══╗             │
  ║      ◄╌ send receipt ╌╌┤    ║             │
  ╚══════╪═════════════════╪════╝             │
         │                 │                  │
         │          ╔══ loop [up to 3 times] ═══════╗
         │          ║      ├── retry write ───►     ║
         │          ╚══════╪══════════════════╪═════╝
         │                 │                  │
         │          ╔══ par [audit] ══════════╪═════╗
         │          ║      ├ write audit row ─►     ║
         │          ╚══════╪══════════════════╪═════╝
         │                 │                  │
  ╔══ break [payment declined] ══╗            │
  ║      ◄ payment failed ╌┤     ║            │
  ╚══════╪═════════════════╪═════╝            │
         │                 │                  │
    ┌────────┐         ┌──────┐         ┌──────────┐
    │ Client │         │ API  │         │ Database │
    └────────┘         └──────┘         └──────────┘

Each section covers interactions by index. Indexes are zero-based, and start and end are both inclusive: in the spec above, the in stock section is "start": 2, "end": 3, the third and fourth interactions, and out of stock is "start": 4, "end": 5, the fifth and sixth. The section’s label is its guard, drawn in brackets. Give every section a guard: an alt section without one raises unlabeled-alt-section. A fragment’s sections run in order without overlapping, and two fragments either nest or stay apart: ranges that cross are a validation error. check reports deep-nesting when a fragment sits more than 3 levels deep.

An activation bar on a lifeline shows when an actor is busy handling a call, and is drawn by default. Set "activations": false at the top level for a lighter drawing. Here is the first diagram again without the bars:

plain.json
{
"type": "sequence",
"actors": [
{"id": "client", "label": "Client"},
{"id": "gateway", "label": "API Gateway"},
{"id": "auth", "label": "Auth Service"},
{"id": "queue", "label": "Audit Queue"}
],
"interactions": [
{"from": "client", "to": "gateway", "label": "POST /login", "style": "solid"},
{"from": "gateway", "to": "auth", "label": "validate credentials", "style": "solid"},
{"from": "auth", "to": "auth", "label": "hash password", "style": "solid"},
{"from": "auth", "to": "gateway", "label": "token", "style": "dashed"},
{"from": "gateway", "to": "queue", "label": "log sign-in", "style": "async"},
{"from": "gateway", "to": "client", "label": "200 OK", "style": "dashed"}
],
"activations": false
}
The login exchange between Client, API Gateway, Auth Service and Audit Queue, drawn without activation bars on the lifelines.The login exchange between Client, API Gateway, Auth Service and Audit Queue, drawn without activation bars on the lifelines.
  ┌────────┐  ┌──────────────┐        ┌──────────────┐  ┌──────────────┐
  │ Client │  │ API Gateway  │        │ Auth Service │  │ Audit Queue  │
  └────────┘  └──────────────┘        └──────────────┘  └──────────────┘
       │              │                       │                 │
       │              │                       │                 │
       ├ POST /login ─►                       │                 │
       │              │                       │                 │
       │              ├ validate credentials ─►                 │
       │              │                       │                 │
       │              │                       ├───┐             │
       │              │                       │   │ hash password
       │              │                       ◄───┘             │
       │              │                       │                 │
       │              ◄╌╌╌╌╌╌╌╌ token ╌╌╌╌╌╌╌╌┤                 │
       │              │                       │                 │
       │              ├────────────── log sign-in ──────────────▷
       │              │                       │                 │
       ◄╌╌ 200 OK ╌╌╌╌┤                       │                 │
       │              │                       │                 │
  ┌────────┐  ┌──────────────┐        ┌──────────────┐  ┌──────────────┐
  │ Client │  │ API Gateway  │        │ Auth Service │  │ Audit Queue  │
  └────────┘  └──────────────┘        └──────────────┘  └──────────────┘

Every actor is a column, so width is the limit. Keep to 8 participants or fewer, which is where seq-too-many-participants fires, and about 6 when the art must fit a terminal. Past that, split the exchange into focused diagrams, or collapse minor participants into one.

For every field and value, see the sequence spec reference.