Publish-Subscribe
Publish-Subscribe routes messages through a broker so publishers and subscribers stay fully decoupled and asynchronous. It enables event-driven fan-out and independent scaling at the cost of broker operations and at-least-once delivery concerns.
Publish-Subscribe is a messaging pattern in which senders, called publishers, emit messages without addressing them to specific receivers, and receivers, called subscribers, express interest in messages without knowing who produces them. An intermediary, a broker or event channel, routes each published message to all interested subscribers. This indirection gives strong decoupling in space, time, and synchronization.
How It Works
Publishers send messages to a topic or channel on the broker rather than to particular subscribers. Subscribers register interest in topics, and the broker delivers each message to every matching subscription. Routing can be topic-based, where subscribers pick named channels, or content-based, where the broker evaluates message attributes against subscriber filters. Because delivery is mediated and usually asynchronous, publishers do not block on subscribers, and subscribers can come and go without the publisher's knowledge.
Brokers add capabilities such as durable subscriptions, retries, ordering guarantees within a partition, and fan-out to many consumers. Technologies range from lightweight in-process buses to systems like Kafka, NATS, and cloud pub/sub services.
When to Use It
Use Publish-Subscribe when many components must react to the same events, when producers and consumers should evolve and scale independently, or when you need asynchronous, non-blocking communication across services. It underpins event-driven architectures, real-time notifications, data pipelines, and integration between microservices.
Trade-offs
The broker is a critical piece of infrastructure to operate, secure, and scale, and it can become a bottleneck or single point of failure if not designed for resilience. Asynchrony complicates reasoning: delivery may be at-least-once, requiring idempotent consumers, and end-to-end debugging needs correlation IDs and tracing. Message ordering and exactly-once semantics are hard to guarantee. Schema evolution must be managed so old and new consumers coexist.
Related Patterns
Observer is the in-process ancestor where the subject references its observers directly; Publish-Subscribe removes that reference via a broker and typically runs across processes. Event Sourcing often publishes domain events to subscribers as they are appended to the log. The Message Broker and Competing Consumers patterns describe the routing intermediary and the scaling model that pub/sub relies on, and the Transactional Outbox pattern is commonly added to guarantee that an event is published exactly when the originating database change commits.
Example
An order service publishes an OrderPlaced event to a topic. Independent subscribers, an inventory service, an email service, and an analytics pipeline, each receive it and act without the order service knowing they exist. Adding a fraud-check subscriber later requires only a new subscription, with no change to the publisher. Because delivery is usually at-least-once, each consumer is written to be idempotent, deduplicating on the event id so a redelivered message does not charge a card twice or send a duplicate email. In practice the choice of broker shapes the guarantees: a log-based system like Kafka retains events and lets new consumers replay history, a lightweight bus like NATS favors low-latency fan-out, and managed cloud services trade operational burden for vendor coupling. Schema evolution is managed with a registry so that older and newer consumers can read the same event stream during a rolling deployment.