Templates
Types
EN

How to Draw a Sequence Diagram: Complete Guide | text2diagram

Learn how to draw a sequence diagram with 5 core elements, 5 message types, and 10 practical rules — then let text2diagram's AI turn plain English into a Mermaid sequence diagram.

Published on ·13 min read
sequence-diagramtutorialapi-designmermaid

1. What is a sequence diagram?

A sequence diagram is a visual description of how a group of actors exchange messages over time. It shows who calls whom · in what order · with what response — nothing more, nothing less. If a flowchart is about the shape of a process, a sequence diagram is about the dialogue between the participants who carry it out.

Sequence diagrams originated in the UML family and remain the industry standard for documenting API integrations, authentication handshakes, distributed system interactions, and any interaction where ordering matters. Time flows top-to-bottom; participants line up left-to-right as vertical lifelines; every message is a labeled arrow between two lifelines at a specific vertical position.

Two properties make sequence diagrams uniquely valuable:

- Every arrow has a source, a target, and a payload. You can't hand-wave "and then the backend does something" — the diagram forces you to name the sender, the receiver, and what was sent. - Vertical position encodes time. Two arrows on the same lifeline mean the second happens after the first. This is why a sequence diagram can convey timing constraints that a flowchart cannot.

2. Why draw a sequence diagram?

Three core reasons — each addresses a real pain in day-to-day API / distributed-system work:

  • Force explicit ownership of each step. Every arrow demands a named source and target. Fuzzy hand-offs like "the system publishes an event" stop being fuzzy the moment they become OrderService -->> Kafka: OrderPlaced.
  • Expose ordering assumptions. Race conditions, missing acks, silent retries all become visible when the timing is drawn. Two arrows on the same lifeline with no return in between? You may have accidentally invented an async call.
  • Bridge design and code review. A senior engineer can walk a sequence diagram in a review meeting in 3 minutes; walking the equivalent 200 lines of Python takes 30. The diagram becomes the source of truth against which the code is judged.

On top of the three "why"s, a well-drawn sequence diagram delivers three concrete benefits:

Kills whiteboard debates about async vs sync. Solid arrows are synchronous, dashed arrows are returns, open triangles are async. The syntax itself settles the argument — no more "wait, does that call block?" during design review.

Catches missing failure paths early. Every arrow that has no matching return, every alt block without an else branch, every loop without a termination condition — all visible in the picture. Cheaper to fix in the diagram than in production.

Speeds up onboarding for API integrators. External integrators reading your OAuth or webhook docs pick up the flow 5× faster from one sequence diagram than from a wall of prose. Stripe, Auth0, Google — every serious API docs page ships sequence diagrams for exactly this reason.

3. Five core elements

A sequence diagram uses a small, disciplined vocabulary. Master these five and you can read 95% of the sequence diagrams you'll ever encounter:

ParticipantThe top-of-diagram rectangle representing an actor: a user, a service, a queue, a database, an external API. Each participant has a vertical lifeline dropping down from its rectangle. Aliases keep the diagram narrow: participant db as PostgreSQL.
LifelineThe vertical dashed line under each participant. Time flows downward along the lifeline. Two events on the same lifeline mean the lower one happens later.
MessageA labeled arrow between two lifelines. The message name goes on the arrow, describing what is being sent — a method call, an HTTP request, a queue payload. Five arrow styles exist (see §4).
ActivationThe narrow vertical rectangle that appears on a lifeline while that participant is actively doing work. Drawn by activate X and deactivate X, or auto-generated with the + / - message prefixes (A ->> +B opens, B -->> -A closes). Optional but highly recommended — it makes concurrency obvious.
Note & FragmentNotes are freeform annotations attached to one or more lifelines (Note right of A: retry on 5xx). Fragments group messages under a control-flow rule — alt / else, opt, loop, par, critical, break. Fragments are what give sequence diagrams their expressive power (see §7).

That's the entire visual grammar. Every sequence diagram — from a two-line "user logs in" example to a fifty-message saga orchestration — is composed of these five nouns.

4. Five message (arrow) types

Mermaid supports five arrow syntaxes, each carrying a distinct meaning. Getting the arrow right is 80% of getting the diagram right:

->> Sync requestSolid line with filled arrowhead. The caller blocks until a response comes back. Use for HTTP request/response, RPC, method invocation. The overwhelmingly most common arrow type — reach for this by default.
-->> ReturnDashed line with filled arrowhead. The response coming back from a prior sync call. Pair every ->> with a -->> unless you deliberately want to show a fire-and-forget.
-) Async sendSolid line with open arrowhead. Caller does not wait — the message goes into a queue, an event bus, or a WebSocket. Ideal for Kafka publishes, WebSocket pushes, SNS notifications.
-> Self-messageAny arrow style where source and target are the same participant. Represents internal work — a service calling its own helper method. Renders as a small loop-back on the lifeline. Use sparingly; too many self-messages usually mean you should factor out a helper participant.
x Lost / found messageSolid line ending in an X (->x for lost, x-> for found). Represents a message that never reaches its target, or arrives from an unknown source. Used to document error paths, dropped connections, or spontaneous events. Advanced use — you'll rarely need it.

5. Mermaid sequence syntax essentials

Mermaid's sequence syntax is small enough to fit on a postcard. The first line must be sequenceDiagram, and every subsequent line is either a participant declaration, a message, or a fragment marker:

sequenceDiagram
    autonumber
    actor User
    participant Web as Web App
    participant API as API Server
    participant DB as PostgreSQL

    User->>Web: click Login
    Web->>+API: POST /auth (email, password)
    API->>+DB: SELECT user WHERE email=?
    DB-->>-API: user row + password_hash
    API->>API: bcrypt.compare(pw, hash)
    alt password matches
        API-->>-Web: 200 OK + JWT
        Web-->>User: redirect to /dashboard
    else password wrong
        API-->>Web: 401 Unauthorized
        Web-->>User: show error banner
    end
    Note right of API: rate-limit: 5 attempts / min

Six things worth noting in the code above:

- autonumber prepends 1., 2., 3. to every message — indispensable when you reference messages by number in prose ("in step 4 we…"). Costs nothing, always turn it on. - actor is used for people (stick-figure icon). participant is used for systems (rectangle). Purely cosmetic, but it helps the reader. - as gives a short alias. Use it when the display name would make lifelines too wide (participant DB as PostgreSQL). - The + / - after the arrow (e.g. ->>+API) auto-activates the target when it starts working and deactivates when it responds. Cleaner than manual activate / deactivate. - alt / else / end is the branching fragment. See §7 for the full fragment catalog. - Note right of X attaches a note to a lifeline. Use Note over X, Y to span multiple lifelines.

6. Ten rules for readable sequence diagrams

The following ten rules come from reviewing hundreds of production sequence diagrams and observing what makes readers understand them in 30 seconds vs 5 minutes:

  • One diagram, one story. Every sequence diagram should answer a single question — "how does login work?", "what happens when payment fails?". If you catch yourself drawing two scenarios in one diagram, split it.
  • 5-9 participants max. More and the diagram becomes a spaghetti wall. Aggregate related components ("Data Layer" instead of Redis + Postgres + Elasticsearch) or split into multiple diagrams.
  • Order participants left-to-right by call frequency. The participant that initiates the most calls goes on the left. This minimizes long horizontal arrows crossing the diagram.
  • Pair every ->> with a -->>. Missing return arrows are the #1 reader confusion — is the caller waiting or moving on? Explicit returns kill the ambiguity. Only omit for genuine fire-and-forget (use -)).
  • Label with verbs and payloads, not method names. ->> API: POST /login (email, pw) beats ->> API: login(). The reader wants to know what was sent, not just the function name.
  • Use autonumber. Free numbering makes every message referenceable in prose, tickets, and code comments ("step 3 in the login sequence"). Never a downside.
  • Activate for compute; skip for straight-through. Show activation bars when a participant does non-trivial work between receiving and responding (database query, external call). Don't clutter with activations for pure pass-through routers.
  • Time flows down, only down. Never draw an arrow that goes upward. If A responds to B, put A's response below B's request. Upward arrows read as time-travel and confuse everyone.
  • One alt branch per outcome — always with an else. If you draw an alt success block, you owe the reader an else failure block. Single-branch alt is code smell; use opt for optional-only paths.
  • Notes for the why, arrows for the what. A well-placed note (Note right of API: retry on 5xx up to 3×) tells the reader why something happens without cluttering the arrow labels. Keep arrows short; put context in notes.

7. Advanced: fragments (alt / opt / loop / par / critical / break)

Fragments are what let sequence diagrams express control flow — branching, looping, parallelism — without turning into flowcharts. Six fragment types cover every real-world case:

alt / elseIf / else / else if. Draw when the flow branches on a condition. Every branch runs mutually exclusively. Always terminate with end. Nesting is legal but keep to 2 levels max — deep nesting quickly becomes unreadable.
optOptional block. For "this may or may not happen" — no else branch. Common uses: cache lookups, logging side effects, optional retries.
loopRepeated messages. Body executes 0-N times. Always write the termination condition in the loop label (loop until success beats bare loop) — otherwise readers assume infinite loop.
par / andParallel execution. Two or more branches happen simultaneously. Use for concurrent API calls, Promise.all, fanout patterns. Each branch is separated by and. The diagram makes concurrency graphically obvious.
critical / optionCritical section with alternates. For "this must happen, but here are the fallbacks". Common in error-handling flows — try primary path, fall back to cached data, fall back to error page. Newer syntax; not all renderers support it — Mermaid does.
breakEarly termination. Marks a break-out from a longer sequence — e.g., "if authentication fails here, skip everything below". Renders as a distinctive frame around the block.

8. Three real-world examples

The best way to internalize sequence diagrams is to read a few from real systems. Below are three canonical patterns with their Mermaid source — you can click "Try it in text2diagram →" under each to generate them from a plain-English description.

Example 1 — OAuth 2.0 authorization code flow

The classic three-party dance: user, client app, auth server. Note the two round-trips through the user's browser — this is what makes OAuth non-trivial to explain in prose.

sequenceDiagram
    autonumber
    actor U as User
    participant C as Client App
    participant AS as Auth Server
    participant RS as Resource API

    U->>C: click "Log in with X"
    C->>U: 302 redirect to AS/authorize
    U->>AS: GET /authorize (client_id, scope)
    AS-->>U: login form
    U->>AS: submit credentials + consent
    AS->>U: 302 redirect back with code
    U->>C: GET /callback?code=abc
    C->>+AS: POST /token (code, client_secret)
    AS-->>-C: access_token + refresh_token
    C->>+RS: GET /user (Bearer access_token)
    RS-->>-C: user profile JSON
    C-->>U: render dashboard

Example 2 — Distributed saga with compensation

The saga pattern is how microservices coordinate a transaction without a 2PC coordinator. Every step publishes an event; every failure triggers a compensating action. Sequence diagrams shine here because the ordering of events is the entire point.

sequenceDiagram
    autonumber
    participant O as OrderService
    participant P as PaymentService
    participant I as InventoryService
    participant B as EventBus

    O->>+B: publish OrderCreated
    B-)P: OrderCreated
    P->>P: charge card
    alt charge succeeds
        P-)B: publish PaymentCharged
        B-)I: PaymentCharged
        I->>I: reserve stock
        alt stock available
            I-)B: publish StockReserved
            B-)O: StockReserved
            O->>-O: mark order Confirmed
        else stock unavailable
            I-)B: publish StockFailed
            B-)P: StockFailed
            P->>P: refund card (compensation)
            P-)B: publish PaymentRefunded
            B-)O: PaymentRefunded
            O->>O: mark order Cancelled
        end
    else charge fails
        P-)B: publish PaymentFailed
        B-)O: PaymentFailed
        O->>O: mark order Cancelled
    end

Example 3 — WebSocket chat with read receipts

Real-time patterns are where async messages (-)) earn their keep. Client A sends, server persists, server pushes to Client B, Client B sends back a receipt. No single call blocks; every arrow is fire-and-forget over an open socket.

sequenceDiagram
    autonumber
    participant A as Client A
    participant S as Server
    participant DB as MessageDB
    participant B as Client B

    A-)S: WS send: hello
    S->>+DB: INSERT message (from=A, to=B)
    DB-->>-S: message_id
    S-)B: WS push: new message
    B->>B: render + auto-mark-read
    B-)S: WS ack: read_receipt(message_id)
    S->>+DB: UPDATE message SET status=read
    DB-->>-S: ok
    S-)A: WS push: read_receipt

9. Common mistakes to avoid

After a few hundred code reviews, the same six mistakes keep appearing:

  • Drawing a flowchart in disguise. If your "sequence diagram" has diamond decisions and branches that loop back over themselves, you actually wanted a flowchart. Sequence diagrams model interactions between actors, not control flow within one actor.
  • Forgetting the return arrow. A ->> API: query with no follow-up -->> Caller: result leaves the reader wondering if the caller blocks, times out, or moved on. Explicit returns cost one line and remove all ambiguity.
  • Alt without else. alt success ... end with no failure branch is a code smell — you're implying "nothing happens on failure", which is almost never true in production. Use opt if it really is optional; otherwise write the else.
  • Too many participants. Ten participants across the top row means fifty possible arrows. If you're above 9, aggregate ("Data Layer" over Redis + Postgres) or split into two diagrams (one for the happy path, one for the error path).
  • Backward arrows. Never draw an arrow that points upward or that resolves above its trigger. Time flows down. Backward arrows read as time-travel and destroy the reader's mental model.
  • Solid arrows for async messages. A ->> implies the caller waits. If the actual runtime behavior is fire-and-forget (Kafka publish, WebSocket push, background job enqueue), use -) — the reader will thank you when they hit a race condition.

10. Draw sequence diagrams with text2diagram

Hand-authoring the syntax above is fine once you know it, but the reason text2diagram exists is to compress "describe an API interaction in English → get a Mermaid sequence diagram" into one sentence. Under the hood:

- Router picks sequenceDiagram automatically for language cues like "then", "sends", "responds", "calls" — you don't have to say "make me a sequence diagram". - Semantic Validator enforces the 10 rules from §6 (missing returns, alt-without-else, backward arrows, over 9 participants) before showing you the result. - Repair Loop self-heals Mermaid syntax errors — if the LLM emits an invalid diagram, the loop retries with the parser error injected into the prompt. Production syntactic error rate is under 1%. - Chat mode asks 1-3 clarifying questions when the request is ambiguous. Typical questions for sequence diagrams: "which participant initiates?", "should this call be synchronous or async?", "what's the failure path?".

Two modes to choose from:

  • Quick mode — one prompt, one shot. Best when your description is already precise (5 participants or fewer, clear ordering, no branching).
  • Chat mode — 1-3 clarifications before drawing. Use for OAuth-scale interactions, saga patterns, anything with error branches. The AI's questions often surface assumptions you'd overlooked.

11. A reusable prompt template

When your interaction is complex, feed the AI a structured template instead of a free-form paragraph. This template covers every real-world case:

Sequence diagram for [scenario name].

Participants:
- [name] ([role], e.g. user / service / queue / db])
- [name] ([role])
- ...

Happy path:
1. [source] -> [target]: [message + payload]
2. [source] -> [target]: [message]
3. ...

Failure paths:
- If [condition]: [alternative sequence]
- If [condition]: [alternative sequence]

Async / concurrent:
- [message A] and [message B] happen in parallel
- [message C] is fire-and-forget (no return expected)

Notes / constraints:
- [participant]: [rate limit / retry policy / timeout]

Fill in the bracketed placeholders, paste into text2diagram (Chat mode recommended for anything beyond 6 participants), and you'll get a diagram that passes all 10 §6 rules on the first try — or a Confrontation card asking about the ambiguities.

12. Wrap-up

Sequence diagrams win when the story is about ordering and message-passing between multiple actors. Reach for them for API integrations, authentication handshakes, distributed system flows, WebSocket / streaming patterns, and anywhere you find yourself saying "and then, and then, and then".

Master the five elements (§3), pick the right arrow (§4), keep the participant count in check (§6 rule 2), and always draw the failure path (§9 mistake 3). Everything else is stylistic polish.

For anything larger than a whiteboard sketch, let text2diagram's Chat mode ask its clarifying questions — the questions themselves often improve the design before a single arrow is drawn.

FAQ

Continue reading

Try text2diagram now

Open the tool
← Back to all tutorials