Relay
Every public action on the network — every post, like, follow, and reply across millions of accounts — is an event. A Relay bundles all of those events into a single realtime stream, the firehose, and hands it to you over one connection.
Those accounts don't all live in one place. Each is hosted on a Personal Data Server (PDS): a server that stores some users' data and emits an event every time that data changes. There are thousands of them across the network. Rather than discovering and connecting to each PDS yourself, you connect to a relay — it crawls the PDS hosts for you, verifies what they send, and re-broadcasts everything as one ordered, de-duplicated stream.
+---------+ +---------+ +---------+ thousands of PDS hosts,
| PDS | | PDS | | PDS | ... each streaming its own
+----+----+ +----+----+ +----+----+ repo events
| | |
+-------------+-------------+
|
v
+-----------+ a Relay aggregates, verifies,
| Relay | and de-duplicates them into one
+-----+-----+ ordered stream
|
v
com.atproto.sync.subscribeRepos <- the firehose
|
+-------------+-------------+
| | |
v v v
feed gens labelers bots, search, your app
A relay does not interpret the records flowing through it — it doesn't know what a "post" or a "like" means. It verifies repository structure and identity signatures, then forwards events to whoever is listening. Making sense of the records is the job of downstream consumers like App Views, feed generators, and labelers.
Looking for protocol-level detail on the event stream and sync model? The AT Protocol docs cover relays, the event stream, and the sync spec in depth.
Bluesky's relays
Bluesky operates a full-network relay. It tracks every repository across the entire network, and it's the default relay that the reference PDS implementation crawls, so most self-hosted PDSes are reachable through it. No authentication is required; the firehose is public.
| Endpoint | Notes |
|---|---|
wss://relay1.us-east.bsky.network | The current Sync 1.1 endpoint, and the one to use for new integrations. Emits prevData on each commit. |
wss://bsky.network | The original firehose endpoint. Still widely used, but does not emit prevData. |
Use the Sync 1.1 endpoint (wss://relay1.us-east.bsky.network) for any new projects.
The prevData field it adds lets consumers detect gaps and verify
repository state without re-fetching whole repos. It also let relays stop
caching their entire broadcast history, which cut storage needs enough to make
public, full-network mirrors
practical.
Bluesky isn't the only relay operator. Relays are part of the open protocol, and several independent relays run at different scales. The endpoints above are the ones Bluesky runs and maintains.
Connecting
To consume the firehose, open a WebSocket to the
com.atproto.sync.subscribeRepos endpoint on a relay:
- Shell
- Go
websocat wss://relay1.us-east.bsky.network/xrpc/com.atproto.sync.subscribeRepos
uri := "wss://relay1.us-east.bsky.network/xrpc/com.atproto.sync.subscribeRepos"
con, _, err := websocket.DefaultDialer.Dial(uri, http.Header{})
Each message is binary-encoded (CBOR), and commits carry CAR slices of the underlying repository. Decoding that stream is involved enough to warrant its own page. See Consuming the firehose for a full, runnable walkthrough.
Do you need the full firehose?
The firehose is core network infrastructure, and its volume grows with the network. If you only care about a few collections (say, just posts and likes) and would rather work with plain JSON than binary CBOR, you probably want Jetstream instead. Jetstream consumes a Relay's firehose on your behalf and fans out a filtered, compressed JSON stream. This is far cheaper to operate for most feed generators, bots, and labelers.
Reach for a Relay firehose directly when you need:
- completeness: every record on the network, with no filtering
- cryptographic verification: the signed commits and MST proofs needed to validate repository state in a zero-trust setting
- your own independent infrastructure: independence from Bluesky-the-org, verified archiving
Rate limits and abuse protection
In addition to aggregating events, a relay enforces rate limits and abuse protections across the PDS hosts it crawls, which keeps the network available even when an individual host misbehaves. If you're consuming at scale, see Rate Limits for the limits that apply to relay and PDS endpoints, and implement client-side backoff so a dropped connection doesn't turn into a thundering herd of reconnects.
Running your own relay
A full-network relay isn't especially expensive to run and doesn't need specialized hardware. Its main cost is network bandwidth, since it ingests from every PDS and fans out to every consumer. You might run a partial relay scoped to a specific community, region, or research use case instead of the whole network.
Bluesky's relay is open source: the implementation lives in the
indigo
repository alongside the rest of our Go tooling.
Next steps
- Consuming the firehose: connect, decode events, and handle them in order.
- Jetstream: the simpler, JSON-based alternative.
- Rate Limits: limits that apply to relay endpoints.