# Choosing a Messaging Pattern (/learn/guides/choosing-a-pattern)



Every messaging pattern is a variation on one of three [interaction styles](/learn/concepts/interaction-styles) — pub/sub fan-out, point-to-point work distribution, or request/reply round-trips — tuned to a particular [delivery guarantee](/learn/concepts/delivery-guarantees). Choosing a pattern is really two questions: *what shape is the conversation*, and *how much can you afford to lose*. Answer those and the pattern falls out.

## Decision Guide [#decision-guide]

Answer a few questions to find the right messaging pattern for your use case.

<PatternDecisionGuide />

### Decision Flowchart [#decision-flowchart]

The same logic as a flowchart. The first fork is the interaction style (does the sender wait for a reply?); the second is the delivery guarantee (can a message be lost?).

<Mermaid
  chart="flowchart TD
    Start{Does the sender need a response?}
    Start -->|Yes| Response{What kind of operation?}
    Start -->|No| NoResponse{Guaranteed delivery needed?}

    Response -->|Execute action| CMD[&#x22;Commands&#x22;]
    Response -->|Request data| QRY[&#x22;Queries&#x22;]

    NoResponse -->|&#x22;No — loss OK&#x22;| EVT[&#x22;Events&#x22;]
    NoResponse -->|Yes| Consumers{How many consumers per message?}

    Consumers -->|One| Q[&#x22;Queues&#x22;]
    Consumers -->|Multiple| Replay{Need historical replay?}

    Replay -->|Yes| ES1[&#x22;Events Store&#x22;]
    Replay -->|&#x22;No, but no loss&#x22;| ES2[&#x22;Events Store&#x22;]

    class CMD command
    class QRY query
    class EVT events
    class Q queue
    class ES1,ES2 store"
/>

*Decision flowchart: the first fork is whether the sender waits for a reply, the second is whether a message can be lost, and the leaves are the five patterns.*

The two branches map straight onto the Fundamentals:

* **The sender waits → request/reply.** [Commands](/learn/concepts/interaction-styles) and Queries are the there-and-back style. Commands carry a write that returns only success/failure; Queries carry a read that returns a full body.
* **The sender hands off and moves on → pub/sub or point-to-point.** Now the [delivery guarantee](/learn/concepts/delivery-guarantees) decides: at-most-once fire-and-forget (Events), or persisted delivery you can replay (Events Store). If each message must be handled by exactly one worker, that is point-to-point work distribution (Queues).

## Pattern Comparison [#pattern-comparison]

| Feature           | Events       | Events Store  | Queues         | Commands      | Queries       |
| ----------------- | ------------ | ------------- | -------------- | ------------- | ------------- |
| Interaction style | Pub/sub      | Pub/sub       | Point-to-point | Request/reply | Request/reply |
| Delivery          | At-most-once | At-least-once | Exactly-once   | At-most-once  | At-most-once  |
| Persistence       | No           | Yes           | Yes            | No            | No            |
| Response          | No           | No            | No             | Executed only | Full body     |
| Ordering          | No           | Sequenced     | FIFO           | N/A           | N/A           |
| Replay            | No           | 6 positions   | No             | No            | No            |
| DLQ               | No           | No            | Yes            | No            | No            |
| Caching           | No           | No            | No             | No            | Yes           |
| Groups            | Yes          | Yes           | N/A            | Yes           | Yes           |

## When to Use Each Pattern [#when-to-use-each-pattern]

### Events — Real-Time Broadcasting [#events--real-time-broadcasting]

Pub/sub fan-out with [at-most-once](/learn/concepts/delivery-guarantees) delivery. Best for real-time notifications, log streaming, live dashboards, and cache invalidation where occasional message loss is acceptable.

**Trade-offs:** Fastest (no disk I/O), but messages are lost if no subscriber is connected — there is no acknowledgement and nothing to replay.

<Mermaid
  chart="sequenceDiagram
    Publisher->>KubeMQ: publish event
    KubeMQ->>Subscriber A: deliver
    KubeMQ->>Subscriber B: deliver
    Note over KubeMQ: Offline subscribers miss the event"
/>

*Events: the publisher fires once, every connected subscriber gets the message, and anyone offline simply misses it.*

### Events Store — Persistent Pub/Sub [#events-store--persistent-pubsub]

Pub/sub fan-out with [at-least-once](/learn/concepts/delivery-guarantees) delivery, persisted to disk. Best for audit trails, event sourcing, cross-service state sync, and any scenario where messages must not be lost.

**Trade-offs:** Higher latency than Events (disk I/O), but subscribers can replay from any point — a late subscriber can read the whole history.

<Mermaid
  chart="sequenceDiagram
    Publisher->>KubeMQ: publish (persisted)
    KubeMQ->>Store: write to disk
    KubeMQ->>Subscriber A: deliver (live)
    Note over Subscriber B: Connects later
    Subscriber B->>KubeMQ: subscribe(StartFromFirst)
    KubeMQ->>Subscriber B: replay all events"
/>

*Events Store: messages are persisted to disk as they are delivered live, so a subscriber that connects later can replay the full history.*

### Queues — Work Distribution [#queues--work-distribution]

Point-to-point competing consumers with [exactly-once](/learn/concepts/delivery-guarantees) processing. Best for order processing, background jobs, webhook delivery, and any task where each message must be handled by exactly one worker.

**Trade-offs:** Requires an explicit ack/nack, but in return you get the full reliability toolkit — DLQ, delayed delivery, visibility timeout, and retry.

<Mermaid
  chart="sequenceDiagram
    Producer->>Queue: send message
    Queue->>Consumer: deliver
    Consumer->>Queue: ack ✓
    Note over Queue: Message removed"
/>

*Queues: one consumer receives the message and acknowledges it, and only then is the message removed from the queue.*

### RPC — Request/Reply [#rpc--requestreply]

The there-and-back interaction style. Best for service-to-service communication, API gateways, CQRS, and device command/control.

**Trade-offs:** Synchronous (sender blocks), but provides a direct response. Commands strip the response body (write semantics), Queries preserve it (read semantics).

<Mermaid
  chart="sequenceDiagram
    Sender->>KubeMQ: send command/query
    KubeMQ->>Responder: deliver request
    Responder->>KubeMQ: send response
    KubeMQ->>Sender: deliver response"
/>

*RPC: the sender blocks while KubeMQ routes the request to a responder and returns the single response back.*

## Combining Patterns [#combining-patterns]

Real systems rarely pick one pattern. The same message often fans out across several styles at once — broadcast for visibility, queue for reliable work. KubeMQ does this with [channel routing](/learn/concepts/channels-and-routing): one send, multiple destinations.

### Event-Driven with Work Queue [#event-driven-with-work-queue]

Broadcast events for monitoring (pub/sub, loss OK), and route critical work to a queue for reliable point-to-point processing.

<Mermaid
  chart="flowchart LR
    Service[&#x22;Service&#x22;]
    KubeMQ{{&#x22;events:notifications<br/>queues:orders&#x22;}}
    Dashboard[&#x22;Dashboard&#x22;]
    Worker[&#x22;Worker&#x22;]

    Service -->|&#x22;events + queues&#x22;| KubeMQ
    KubeMQ -->|event| Dashboard
    KubeMQ -->|queue| Worker

    class Service,Dashboard,Worker client
    class KubeMQ broker"
/>

*Event-driven with work queue: a single send fans out to a dashboard for monitoring and to a queue for reliable point-to-point processing.*

### CQRS with Events [#cqrs-with-events]

Commands write data (request/reply), events propagate the change (pub/sub), queries read projections (request/reply).

<Mermaid
  chart="flowchart LR
    Client[&#x22;Client&#x22;]
    WriteService[&#x22;Write Service&#x22;]
    EventStore[&#x22;Events Store&#x22;]
    ReadService[&#x22;Read Service&#x22;]

    Client -->|command| WriteService
    WriteService -->|event| EventStore
    EventStore -->|subscribe| ReadService
    Client -->|query| ReadService

    class Client,WriteService,ReadService client
    class EventStore store"
/>

*CQRS with events: commands write through the event store, the read service subscribes to build projections, and clients query that read side.*

### Fan-Out with Routing [#fan-out-with-routing]

Publish once, deliver to multiple patterns using channel routing syntax.

| Syntax                              | Meaning                   |
| ----------------------------------- | ------------------------- |
| `events:channel-a;events:channel-b` | Two event channels        |
| `events:live;events_store:archive`  | Event + persistent copy   |
| `events:notify;queues:process`      | Broadcast + reliable work |

## Decision Matrix [#decision-matrix]

| Requirement                 | Recommended Pattern  |
| --------------------------- | -------------------- |
| Real-time notifications     | Events               |
| Log/metric streaming        | Events               |
| Cache invalidation          | Events               |
| Audit trail                 | Events Store         |
| Event sourcing              | Events Store         |
| Cross-service state sync    | Events Store         |
| Order processing            | Queues               |
| Background jobs             | Queues               |
| Scheduled/delayed tasks     | Queues               |
| Webhook delivery with retry | Queues               |
| Service-to-service calls    | RPC Commands/Queries |
| API gateway backend         | RPC Commands/Queries |
| Device command & control    | RPC Commands         |
| Cached lookups              | RPC Queries          |
