What is webhook fan-out?
Webhook fan-out (often written fanout) is the pattern of taking a single event and delivering it to every endpoint subscribed to it, which can be hundreds or thousands of them. Each delivery is an independent HTTP request with its own retry state, so one slow or broken subscriber cannot hold up the rest.
Why one event becomes many requests
A webhook sender publishes events, not messages addressed to a particular recipient. When an order ships, the sender does not know or care who wants to hear about it; it knows the event type and looks up every endpoint subscribed to that type. A single customer might register three endpoints, one per environment. A busy account might have a dozen. Multiply that across a customer base and one business event turns into a burst of HTTP requests that all need to succeed independently.
That multiplication is what makes fan-out its own problem rather than a detail of sending. Delivering one webhook well means signing a request and retrying it if it fails. Delivering ten thousand copies means doing that concurrently while keeping every result separate.
Where naive fan-out breaks
The obvious implementation loops over subscribers and posts to each one inline. It works until the first endpoint that does not respond.
- Head-of-line blocking. One endpoint that takes 30 seconds to time out delays every delivery queued behind it, so a single unresponsive subscriber stalls the whole fan-out.
- Shared failure state. If the loop retries the whole batch on failure, subscribers that already succeeded get the event twice.
- Backpressure on the application. Fanning out inside the request that created the event makes your API latency depend on other people's servers.
- Noisy-neighbor load. A large customer with many endpoints can consume the worker pool everyone else's deliveries need.
The fix is to fan out into a queue rather than over the wire. The event is written once, expanded into one message per endpoint, and each message is delivered by a worker that owns only that delivery.
Keeping subscribers isolated
Once each delivery is its own unit of work, isolation follows. Every endpoint gets its own retry schedule with exponential backoff, so a subscriber that is down for an hour retries on its own timeline while healthy subscribers see no delay. Deliveries that exhaust their retries land in a dead-letter queue for that endpoint alone. A rate limit per endpoint stops a fan-out burst from overwhelming a receiver that cannot absorb it, and circuit breaking pauses delivery to endpoints that have been failing long enough to be considered dead.
Ordering is the tradeoff. Concurrent, independently retried deliveries mean two events for the same object can reach a subscriber out of order, so payloads need timestamps or sequence numbers that let receivers sort it out.
Fan-out over HTTP versus inside a broker
Fan-out is not unique to webhooks. A message broker does the same thing with a topic exchange. The difference is where the subscribers live: broker fan-out targets consumers you operate, on a protocol you control, inside your network. Webhook fan-out targets endpoints your customers operate, over the public internet, with no way to fix a broken consumer. That is why the webhook version needs per-endpoint retries and delivery logs a broker can leave out.
Building this yourself means a queue, a worker pool, per-endpoint state, and a way for customers to see their own deliveries. Svix provides that layer as a service: send one event to the API and it handles the expansion, signing, retries, and logging for every subscribed endpoint. If you would rather build it, our guide to building a webhook sender walks through the pieces.
Frequently asked questions
How is webhook fan-out different from a broadcast?
A broadcast sends the same message to everyone. Fan-out sends an event only to the endpoints subscribed to that event type, and treats each delivery as a separate attempt with its own retries, rate limit, and failure state.
Does webhook fan-out guarantee ordering?
Not by default. Deliveries run concurrently and failed ones retry later, so a subscriber can receive events out of order. Include a timestamp or sequence number in the payload so receivers can reorder or discard stale events.
How do you stop one bad endpoint from slowing everyone down?
Give each delivery its own queued work item rather than looping over subscribers inline. Then a timeout, retry, or circuit break applies to that endpoint only, and other subscribers are delivered on schedule.