# Understanding the Relationship Between iroh, iroh-blobs, iroh-gossip, and iroh-docs

> Discover how iroh's core QUIC transport powers iroh-blobs, iroh-gossip, and iroh-docs for content storage, message dissemination, and document synchronization.

- Repository: [number zero/iroh](https://github.com/n0-computer/iroh)
- Tags: deep-dive
- Published: 2026-07-14

---

**`iroh` provides the core peer-to-peer QUIC transport layer, while `iroh-blobs`, `iroh-gossip`, and `iroh-docs` are protocol-specific extensions that leverage this transport to enable content-addressed storage, message dissemination, and document synchronization.**

The `n0-computer/iroh` repository organizes these capabilities into a modular architecture where the foundational networking stack remains separate from higher-level data protocols. Understanding how these crates interact helps developers build distributed applications that combine reliable connectivity with specific data-management semantics.

## The Core Transport Layer (iroh)

The **`iroh`** crate implements the foundational peer-to-peer networking stack. According to the source code in [`iroh/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs), this crate provides **QUIC transport**, relay handling, hole-punching, and address-lookup services through a unified `Endpoint` API.

The core library handles encryption and connection establishment between peers but does not define application-level protocols for data exchange. Instead, it exposes generic stream and datagram APIs that higher-level crates consume. When you bind an endpoint using `Endpoint::bind(presets::N0).await?`, you create a shared resource that manages NAT traversal, relay fallback, and connection pooling for all protocol extensions.

## Protocol-Specific Extensions

The higher-level protocols live in separate workspace crates that `iroh` re-exports under feature flags. You enable these by adding `features = ["blobs", "gossip", "docs"]` to your [`Cargo.toml`](https://github.com/n0-computer/iroh/blob/main/Cargo.toml) dependency.

### iroh-blobs (Content-Addressed Storage)

**`iroh-blobs`** implements a BLAKE3-based content-addressed blob store protocol. This crate handles uploading, downloading, and managing large binary objects ranging from kilobytes to terabytes.

The blobs protocol operates over QUIC streams opened through the core `iroh` endpoint. In [`iroh/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs), the crate re-exports `iroh_blobs::Client` and `iroh_blobs::Server` as `iroh::blobs`, allowing applications to construct clients directly from an existing endpoint:

```rust
use iroh::blobs::Client;

let blobs = Client::new(endpoint.clone());
let hash = blobs.put(b"Hello, world!").await?;

```

Internally, the blobs client opens bidirectional QUIC streams negotiated via the ALPN protocol identifier, using the same relay and hole-punching infrastructure provided by the base `iroh` crate.

### iroh-gossip (Publish-Subscribe Overlay)

**`iroh-gossip`** provides a scalable publish-subscribe overlay network designed for low-resource devices. It implements topic-based message dissemination where peers can join topics and broadcast messages to all participants.

The gossip implementation registers itself as a protocol handler using `Endpoint::add_protocol_handler`. When you create a `GossipClient` via `iroh::gossip::Client::new(endpoint.clone())`, the client opens its own QUIC streams through the shared endpoint while maintaining its own routing tables and fan-out algorithms.

This design allows gossip traffic to coexist with blobs transfers on the same underlying connections, sharing the NAT traversal and relay infrastructure without protocol interference.

### iroh-docs (Eventually-Consistent Key-Value Store)

**`iroh-docs`** builds upon the blobs protocol to provide an eventually-consistent document store. Rather than implementing its own transport, this crate composes the `iroh-blobs` client to store document revisions as content-addressed blobs.

When you initialize a docs client using `iroh::docs::Client::new(endpoint)`, the crate internally creates both a blobs client and a gossip client if needed. Documents store their content as blobs and track metadata using the gossip protocol for synchronization between peers.

The high-level `Docs` API abstracts these underlying dependencies, but the architecture remains: `iroh-docs` depends on `iroh-blobs`, which depends on `iroh` for transport.

## Practical Integration Patterns

A typical application creates a single `Endpoint` instance and shares it across all protocol clients. This co-location minimizes connection overhead while allowing blobs, gossip, and docs traffic to multiplex over the same QUIC connections.

```rust
use iroh::{Endpoint, endpoint::presets};
use iroh::blobs::Client as BlobsClient;
use iroh::gossip::Client as GossipClient;
use iroh::docs::Client as DocsClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Bind once: handles all networking, relays, and hole-punching
    let ep = Endpoint::bind(presets::N0).await?;
    
    // Initialize protocol clients sharing the endpoint
    let blobs = BlobsClient::new(ep.clone());
    let gossip = GossipClient::new(ep.clone());
    let docs = DocsClient::new(ep.clone());
    
    // Store a blob and announce it via gossip
    let data = b"distributed systems data";
    let hash = blobs.put(data.as_ref()).await?;
    gossip.publish(b"data-topic", hash.as_bytes()).await?;
    
    // Store structured data via docs (uses blobs internally)
    let doc_id = docs.put(b"{\"key\":\"value\"}").await?;
    
    Ok(())
}

```

This pattern demonstrates how the crates compose: `iroh` provides the `Endpoint`, `iroh-blobs` provides content-addressed storage, `iroh-gossip` provides discovery, and `iroh-docs` provides higher-level document semantics.

## Key Source Files and Architecture

The monorepo structure in `n0-computer/iroh` reflects these architectural boundaries:

- **[`iroh/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs)** – Defines the core `Endpoint` struct and re-exports `iroh_blobs`, `iroh_gossip`, and `iroh_docs` when their respective features are enabled. This file demonstrates the composition pattern where external crates are integrated into the public API.

- **[`iroh/README.md`](https://github.com/n0-computer/iroh/blob/main/iroh/README.md)** – Documents the bundled protocols and explains how to enable feature flags for specific functionality.

- **[`Cargo.toml`](https://github.com/n0-computer/iroh/blob/main/Cargo.toml) (workspace root)** – Lists `iroh-blobs`, `iroh-gossip`, and `iroh-docs` as workspace members, ensuring version alignment across the protocol stack.

- **[`iroh/examples/search.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/search.rs)** – Provides a practical example of using the blobs protocol to search for and retrieve content across the network.

These files confirm that while the protocol crates maintain separate repositories (or workspace directories), they remain version-aligned and are designed to function together through the shared `Endpoint` abstraction.

## Summary

- **`iroh`** provides the foundational QUIC transport, relay handling, and connection management required for peer-to-peer networking.
- **`iroh-blobs`** implements content-addressed storage using BLAKE3 hashes, transmitting data over QUIC streams opened through the core endpoint.
- **`iroh-gossip`** offers topic-based message dissemination by registering protocol handlers with the shared endpoint.
- **`iroh-docs`** composes blobs and gossip to provide eventually-consistent document storage without implementing its own transport layer.
- Applications typically bind a single `Endpoint` and clone it to construct clients for all three protocols, enabling efficient connection reuse.

## Frequently Asked Questions

### Can I use iroh-blobs without iroh-gossip?

Yes. **`iroh-blobs`** depends only on the core `iroh` crate for transport. You can construct a `blobs::Client` using just an `Endpoint` without enabling the `gossip` feature. However, if you want to discover content without pre-sharing hashes, you would need to implement your own discovery mechanism or use `iroh-gossip` to announce content availability.

### Does iroh-docs require both blobs and gossip?

**`iroh-docs`** requires **`iroh-blobs`** to store document content, as it serializes documents as blobs internally. While it can function without gossip for local storage, the synchronization and replication features typically require **`iroh-gossip`** to broadcast document updates to peers. The `DocsClient` automatically initializes these dependencies when constructed via `iroh::docs::Client::new(endpoint)`.

### How do feature flags affect the relationship between these crates?

The `iroh` crate uses Cargo feature flags to conditionally compile re-exports of the protocol crates. When you specify `features = ["blobs", "gossip"]` in your [`Cargo.toml`](https://github.com/n0-computer/iroh/blob/main/Cargo.toml), the `iroh` crate includes `iroh-blobs` and `iroh-gossip` as dependencies and exposes them as `iroh::blobs` and `iroh::gossip`. This allows you to keep binary sizes smaller by including only the protocols your application requires.

### Is the Endpoint thread-safe for sharing between protocols?

Yes. The **`Endpoint`** type implements `Clone` and is designed to be shared across protocol clients. When you write `let blobs = Client::new(ep.clone())` and `let gossip = Client::new(ep)`, both clients maintain references to the same underlying connection pool, relay state, and hole-punching coordination. This sharing is essential for efficient NAT traversal, as it prevents duplicate relay connections.