What is the Pub/Sub (Publish-Subscribe) Pattern?

Last updated: July 2026

Pub/sub is a messaging pattern where publishers send messages to topics on a broker, and every subscriber to a topic gets a copy. Its whole value is what the parties don’t know: publishers never learn who is listening, subscribers never learn who sent — the broker’s indirection decouples them in space (different systems), time (subscribers may be offline), and synchronization (publish returns immediately). Add subscribers without touching publishers; that is the pattern’s quiet superpower.

Key takeaways

QuestionAnswer
The castPublisher → message → topic → broker → subscribers (each gets a copy)
vs. a queueA queue distributes work to one consumer; pub/sub duplicates it to all
vs. observerObserver is in-process and synchronous; pub/sub is brokered and async
The default stanceAt-least-once delivery + idempotent handlers
The fine printNo replies, no default ordering, no atomic transactions across the broker

The pattern in code

Every pub/sub API reduces to two verbs, whatever the broker:

// Subscribers — register interest in a topic
broker.subscribe('orders.paid', (msg) => fulfill(msg));   // service A
broker.subscribe('orders.paid', (msg) => notifyUser(msg)); // service B — its own copy

// Publisher — fire and forget
broker.publish('orders.paid', { orderId: 'o-1187' });
// The publisher never learns who received it — or whether anyone did.

The same shape at the client edge, where a live-query subscription is the topic and a database write is the publish:

// JavaScript / Node.js — Back4app JS SDK
// Pub/sub at the edge: live queries subscribe, saves publish
// Subscriber — register interest in a topic
const topic = new Parse.Query('Event');
topic.equalTo('topic', 'orders');
const sub = await topic.subscribe();
sub.on('create', (event) => handle(event.get('payload')));

// Publisher — fire and forget; no knowledge of subscribers
const event = new Parse.Object('Event');
event.set('topic', 'orders');
event.set('payload', { orderId: 'o-1187', status: 'paid' });
await event.save();

How pub/sub works

Publish-subscribe message flow through a brokerA publisher sends a message to a named topic on a message broker. The broker matches the topic against registered subscriptions and delivers an independent copy of the message to each subscriber, which acknowledge processing separately.

publish(orders.paid, msg)

copy 1

copy 2

copy 3

Publisher
(fire & forget)

Broker
topic: orders.paid

Subscriber A
fulfillment

Subscriber B
notifications

Subscriber C
analytics

A publisher sends a message to a named topic on a message broker. The broker matches the topic against registered subscriptions and delivers an independent copy of the message to each subscriber, which acknowledge processing separately.

The broker does four jobs: accept publishes and return immediately; match each message against subscriptions (by topic name, hierarchically — orders.* — or by content attributes); deliver an independent copy per subscriber, retrying per its guarantee level; and retain messages for offline subscribers where durability is configured — the time-decoupling that lets a service deploy at noon and catch up on what it missed. One vocabulary note worth its sentence: a message is the envelope; an event — “this happened, past tense” — is what pub/sub usually carries, and whether it carries just the fact or the full state is Fowler’s event-notification vs. event-carried-state-transfer distinction.

Pub/sub vs. message queues vs. observer pattern

The two confusions, settled in one table:

Pub/subMessage queueObserver
DeliveryEvery subscriber gets a copyExactly one worker consumes each messageSubject calls each observer
PurposeBroadcast eventsDistribute workReact to state in-process
CouplingNone — broker-mediatedNone — queue-mediatedDirect object references
TimingAsyncAsyncUsually synchronous
BoundaryAcross processes/systemsAcross workersInside one process
Canonical shape1 event → N reactionsN jobs → M workers1 object → its listeners

The soundbite that survives the meeting: a queue distributes work; pub/sub duplicates it. And observer is not “small pub/sub” — the broker’s indirection is precisely what observer lacks, which is why refactoring an observer into pub/sub is an architectural change, not a rename. In practice brokers offer both shapes: consumer groups turn a topic into a queue per group (Kafka’s signature move), fanout exchanges turn a queue system into pub/sub.

Delivery guarantees: at-most-once vs. at-least-once vs. exactly-once

GuaranteeFailure modeCostYour handler mustChoose when
At-most-onceMessages can vanishCheapest, fastestTolerate gapsEphemeral data: presence, tickers, metrics
At-least-onceDuplicates arriveAcks + retriesBe idempotentThe default for business events
Exactly-onceConstrained, complexDedup + coordinationStill be idempotentNarrow paths where brokers support it

MQTT’s QoS levels 0/1/2 map to these three exactly — a tidy confirmation the trichotomy is fundamental, not vendor marketing. The engineering truth: end-to-end exactly-once is unachievable in general (the Two Generals’ problem wearing a broker badge); systems that advertise it combine at-least-once delivery with deduplication. Which is why the pattern’s real contract is written in your handler: at-least-once + idempotency — dedup on a message ID, use upserts keyed on the entity, or version-check before applying — turns duplicates from bugs into no-ops.

Ordering, dead letters, and topic design

Three operational realities the intro diagrams skip. Ordering: fan-out to parallel consumers has no global order; brokers restore it per partition or ordering key at the price of parallelism — design handlers to apply events by entity ID and version, not arrival sequence, and the problem mostly dissolves. Poison messages: a message whose processing always throws will retry forever under at-least-once; cap delivery attempts and route failures to a dead-letter queue for triage, or one bad event stalls the topic. Topic design: name hierarchically (orders.paid, orders.refunded, wildcard orders.*), keep granularity at the level subscribers actually differ on, and evolve message schemas additively — subscribers ignore unknown fields; breaking changes get a new versioned topic (orders.v2) with a migration window, exactly like an API version.

Common use cases

  • Microservice integration — services owned by different teams reacting to each other’s events without direct calls or shared deploy schedules.
  • Real-time client features — chat fan-out, live dashboards, presence: pub/sub over WebSockets at the edge.
  • IoT telemetry — thousands of devices publishing over MQTT; consumers from alerting to analytics subscribing independently.
  • Cache invalidation and replication — one write published, every cache and replica notified.
  • Parallel processing pipelines — one event triggering fulfillment, notification, and analytics simultaneously, each at its own pace.

Should you use pub/sub? A decision matrix

Pub/sub fits when…Prefer something else when…
One event interests several independent consumersOne consumer: a queue, or just a call
Producers and consumers deploy independentlyCaller needs the answer now → request-response
Eventual consistency is acceptableAtomicity across parties required → transactions/Saga
Subscribers come and go over timeStrict global ordering is non-negotiable
Spiky load needs buffering between systemsThe whole system fits in one process → observer

Limitations and trade-offs

  • Debugging crosses a broker. “Who consumed this and why did it fail?” needs correlation IDs and tracing; the decoupling that frees teams also hides causality.
  • No replies by design. Workflows needing responses must model them as further messages — added latency and state machines where a function call once sufficed.
  • The broker is infrastructure. Availability, capacity, security, and retention policies of the messaging layer become platform work; a down broker is an outage multiplier.
  • Publisher blindness cuts both ways. Publishers can’t observe subscriber health; a silently failing consumer loses data unless dead-letter monitoring exists.
  • Guarantees cost throughput. Ordering keys serialize, exactly-once coordinates, durability persists — each strengthening of semantics spends performance; buy only what the data needs.

Pub/sub on Back4app

Back4app is an open-source Backend-as-a-Service (BaaS) platform that combines a managed database, auto-generated REST and GraphQL APIs, authentication, file storage, and Cloud Code serverless functions. The pattern shows up here at the client edge: Live Queries are pub/sub where the query is the topic — subscribers register a predicate, any write that matches is published to every subscriber over a managed WebSocket fleet, with permissions checked per subscriber and fan-out handled by the platform, as in the code tabs above. Server-side reactions compose the same way: Cloud Code triggers subscribe to data changes (afterSave as a topic subscription in spirit), and scheduled functions drain work published as rows. For heavy inter-service streaming you would still reach for a dedicated broker like Kafka or RabbitMQ — but for the common product cases, broadcast-on-change ships with the backend.

Frequently asked questions

What is pub/sub in simple terms?

A messaging pattern where senders (publishers) post messages to named topics on a broker, and every component that subscribed to that topic receives its own copy — publishers and subscribers never know about each other. Think radio broadcast: the station transmits on a frequency; whoever tunes in, hears it.

What is the difference between pub/sub and a message queue?

A queue distributes work; pub/sub duplicates it. In a queue, each message is consumed by exactly one worker — the tool for spreading jobs across a pool. In pub/sub, every subscriber to the topic gets a copy — the tool for broadcasting events to independently interested parties.

What is the difference between pub/sub and the observer pattern?

Observer is in-process: the subject holds direct references to its observers and usually calls them synchronously. Pub/sub inserts a broker between the parties, making them fully decoupled, typically asynchronous, and able to live in different processes, languages, and deployments. One is a design pattern inside an app; the other is an architecture between systems.

How is pub/sub different from request-response?

Request-response is synchronous and one-to-one — the caller blocks until an answer returns. Pub/sub is asynchronous, one-way, and one-to-many: publish returns immediately and no reply exists. If a subscriber must answer, that is a separate message on a reply channel, not a return value.

What is a topic in pub/sub?

A named logical channel that categorizes messages: publishers address the topic, and the broker delivers each message to all of that topic's subscribers. Filtering can be topic-based (subscribe by name, often hierarchically — orders.*) or content-based, where the broker matches on message attributes.

What delivery guarantees does pub/sub offer?

Three levels. At-most-once: fire and forget — fast, may lose messages. At-least-once: retry until acknowledged — the common default, produces occasional duplicates. Exactly-once: deduplication plus coordination — expensive, constrained, and impossible to guarantee end-to-end in general. The practical stance: at-least-once delivery with idempotent handlers.

Does pub/sub guarantee message ordering?

Not by default — messages fan out to parallel subscribers, and global order fights parallelism. Brokers can order within a partition or ordering key at a throughput cost. The robust design assumes ordering only where explicitly configured and writes handlers that tolerate out-of-order arrival.

Is Kafka pub/sub?

Yes, with a twist: Apache Kafka implements publish-subscribe semantics over a partitioned, durable, replayable commit log. Within a consumer group it behaves like a queue (each message to one member); across groups it behaves like pub/sub (each group gets a copy) — which is why it is usually called event streaming.

When should you not use pub/sub?

When the caller needs an immediate answer (request-response), when operations must be atomic across producer and consumers (a broker cannot join a transaction — see the Saga pattern), when strict global ordering is required, or when the system is small enough that a broker adds more operational surface than it removes.

Related terms

Compare with

Further reading

Ready to build your backend?

Start your project on Back4app in minutes — database, auth, APIs, and Cloud Code included. No credit card required.

Written and reviewed by Back4app Engineering, Back4app Engineering · Published 2026-07-24