Saturday, 31 October 2026

What is the difference between a Service Bus Queue and a Topic?

Service Bus Queue vs. Topic

The core difference is the delivery model: a queue delivers each message to exactly one consumer, while a topic delivers a copy of each message to every interested subscriber.

Queue: point-to-point

Senders put messages on the queue, and receivers pull from it. If several receivers listen to the same queue, they are competing consumers: each message goes to only one of them, so adding receivers spreads the load.

Sender(s) ──► [ Queue ] ──► Receiver A  (or B, or C; one gets each message)

Topic: publish/subscribe

Senders publish to a topic, but receivers don't read from the topic itself. They read from subscriptions, each of which acts like its own virtual queue. Every subscription receives its own copy of each message that matches its filter.

                      ┌─► [ Subscription: billing ]   ──► Billing service
Sender ──► [ Topic ] ─┼─► [ Subscription: shipping ]  ──► Shipping service
                      └─► [ Subscription: analytics ] ──► Analytics service

Within a single subscription, multiple consumers still compete, so you can scale out each subscriber independently.

Side-by-side

Queue Topic + subscriptions
Pattern Point-to-point Publish/subscribe (one-to-many)
Copies per message One, consumed once One per matching subscription
Receivers read from The queue A subscription (not the topic)
Sender knows the receivers? Effectively one logical consumer No, the sender is unaware of subscribers
Filtering None Rules and filters per subscription (SQL or correlation filters, with optional actions)
Adding a new consumer Competes with existing ones for messages Create a new subscription; existing ones are unaffected
Dead-letter queue One DLQ One DLQ per subscription
Tiers Standard and Premium Standard and Premium

Filters on subscriptions

Topics get much of their power from subscription rules:

// Only receive orders from the EU
await adminClient.CreateSubscriptionAsync(
    new CreateSubscriptionOptions("orders", "eu-orders"),
    new CreateRuleOptions("EuOnly", new SqlRuleFilter("region = 'EU'")));

A subscription with no rule gets everything by default. Note that a subscription's default rule is "match all", so if you add your own filter, remove the default rule or it will still match every message.

Sending and receiving in code

The code is nearly identical. The sender doesn't care which it targets, and only the receiver changes:

// Send (queue name or topic name)
var sender = client.CreateSender("orders");
await sender.SendMessageAsync(new ServiceBusMessage("Order #1234 placed"));

// Receive from a queue
var queueReceiver = client.CreateReceiver("orders");

// Receive from a topic subscription
var subReceiver = client.CreateReceiver("orders", "billing");

Because sending code is the same, you can start with a queue and move to a topic later without changing producers (you'd recreate the entity, though, as a queue can't be converted into a topic).

When to use which

Use a queue when:

  • One service should process each message (work distribution, task processing).
  • You want load leveling or competing consumers for throughput.
  • The sender and receiver are tightly paired, e.g. "process this payment."

Use a topic when:

  • Multiple independent systems must react to the same event (an "order placed" event consumed by billing, shipping, and notifications).
  • Different consumers want different subsets of messages (via filters).
  • You expect to add new consumers over time without touching the publisher.

Shared behavior

Queues and subscriptions share the same features: peek-lock, dead-lettering, sessions, scheduled messages, duplicate detection (configured at the topic level for topics), and TTL. A subscription is, in effect, a queue fed by a topic.

Rule of thumb

  • Command ("do this work") → queue
  • Event ("this happened") → topic

If you have a single consumer today but may add more, a topic with one subscription is a cheap way to keep your options open.

No comments:

Post a Comment

Note: only a member of this blog may post a comment.