All posts
MermaidSequence DiagramsControl Flow

Mermaid loop and alt blocks: conditional flows explained

5 min readThe MermaidCreator team

Most real workflows branch. A payment API retries on timeout. Auth returns 401 on invalid credentials. A polling worker loops until the job completes. Sequence diagrams that ignore these branching paths teach a false simplicity.

Mermaid's alt, else, and loop blocks let you show decision logic and retries inside a single diagram without repeating arrows or splitting across multiple drawings.

alt/else blocks for branching

The alt block (alternation) works like an if/else statement in code. You write one flow path, mark the condition, then show what happens if the condition is false:

sequenceDiagram
    participant C as Client
    participant API as Payment API
    participant DB as Database

    C->>API: POST /charge { amount, card }
    API->>DB: SELECT card_token WHERE card_id=?
    DB-->>API: token (or null)
    alt Card found
        API->>API: Process charge with token
        API-->>C: 200 OK { transaction_id }
    else Card not found
        API-->>C: 400 Bad Request { error }
    end

The alt block reads naturally: if the condition in the label is true, follow the top path; otherwise, follow the else path. Readers don't need two separate diagrams — both outcomes live in one.

Multiple branches with else if

For more than two branches, chain else if (written as else in Mermaid):

sequenceDiagram
    participant C as Client
    participant Auth as Auth Service
    participant DB as User DB

    C->>Auth: POST /login { email, password }
    Auth->>DB: SELECT * FROM users WHERE email=?
    DB-->>Auth: User record (or null)
    
    alt User found
        Auth->>Auth: Verify password hash
        alt Password matches
            Auth-->>C: 200 OK { token }
        else Password invalid
            Auth-->>C: 401 Unauthorized
        end
    else User not found
        Auth-->>C: 404 Not Found
    end

Stack alt/else blocks to model cascading decision trees. Each condition gets its own line of reasoning.

loop blocks for retries and polling

The loop block shows repeated actions without forcing you to copy arrows multiple times. It's perfect for retries, polling, and any "keep doing this until condition X" pattern:

sequenceDiagram
    participant C as Client
    participant API as Job API
    participant Worker as Background Worker

    C->>API: POST /jobs { task: "process-data" }
    API-->>C: 202 Accepted { job_id: 42 }
    
    loop Poll every 2 seconds (max 10 attempts)
        C->>API: GET /jobs/42/status
        API-->>C: { status: "processing" }
    end
    
    C->>API: GET /jobs/42/status
    API-->>C: { status: "done", result: "..." }

The label describes the loop condition — readers see immediately that the client polls repeatedly until the job finishes.

Combining loop and alt for robust flows

Real systems combine both. Here's a fetch-with-retries pattern:

sequenceDiagram
    participant C as Client
    participant API as Downstream API

    C->>API: GET /resource/123
    
    loop Retry up to 3 times on timeout
        alt Responds within 5s
            API-->>C: 200 OK { data }
            break
        else Timeout
            Note right of C: Retry...
        end
    end

The break statement exits the loop when the condition succeeds. Readers see the retry strategy without a wall of arrows.

Practical patterns

Exponential backoff retry (conceptual):

sequenceDiagram
    participant C as Client
    participant API as External API
    
    C->>API: POST /webhook-notify
    
    loop Retry with backoff (1s, 2s, 4s, 8s)
        alt Responds with 2xx
            API-->>C: Success
            break
        else 5xx server error
            Note right of C: Wait, then retry
        else Network timeout
            Note right of C: Wait, then retry
        end
    end

Cascading fallbacks:

sequenceDiagram
    participant C as Client
    participant Cache as Redis Cache
    participant DB as Primary DB
    participant Backup as Backup DB

    C->>Cache: GET user:42
    alt Cache hit
        Cache-->>C: { user }
    else Cache miss
        C->>DB: SELECT * FROM users WHERE id=42
        alt Primary responds
            DB-->>C: { user }
        else Primary timeout
            C->>Backup: SELECT * FROM users WHERE id=42
            Backup-->>C: { user }
        end
    end

When to use each block

alt/else: Your flow has a decision point. Show both branches inline rather than as separate diagrams. One diagram, two paths.

loop: The same action repeats. Polling, retries, batch processing. The loop label tells readers the termination condition.

Combine both: Error-recovery patterns where you loop on a condition and break on success.

Avoiding over-complexity

A rule of thumb: if your diagram has more than 3 nested blocks or loops, consider splitting it into two diagrams. A readable diagram teaches; a crowded one confuses.

Split when:

  • The loop or alt block is conceptually separate (e.g., "here's the happy path; here's error recovery")
  • The diagram is longer than a typical function (roughly 15–20 lines of Mermaid syntax)
  • A second diagram would make the first easier to explain

Keep it focused. A diagram about JWT auth doesn't need to show the full retry strategy for the database query; mention it in prose instead.

FAQ

Q: Can I use && or || logic in alt conditions? A: The condition text is just a label for readers — it's not executable. Write what makes sense in plain English: "Retry count < 3 and timeout", "User has admin role or owns resource", etc.

Q: What's the difference between loop and par? A: loop shows sequential repetition (do this multiple times in a row). par (parallel) shows concurrent actions. Use loop for retries and polling.

Q: How do I show an else if without nesting? A: Write multiple else blocks inside one alt. Each else label describes a new condition branch.

Try drawing your next error-recovery pattern in the MermaidCreator editor — seeing loops and alts render makes the syntax stick fast.

Related posts