Understanding the Relationship Between iroh, iroh-blobs, iroh-gossip, and iroh-docs
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, 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 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, the crate re-exports iroh_blobs::Client and iroh_blobs::Server as iroh::blobs, allowing applications to construct clients directly from an existing endpoint:
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.
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– Defines the coreEndpointstruct and re-exportsiroh_blobs,iroh_gossip, andiroh_docswhen their respective features are enabled. This file demonstrates the composition pattern where external crates are integrated into the public API. -
iroh/README.md– Documents the bundled protocols and explains how to enable feature flags for specific functionality. -
Cargo.toml(workspace root) – Listsiroh-blobs,iroh-gossip, andiroh-docsas workspace members, ensuring version alignment across the protocol stack. -
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
irohprovides the foundational QUIC transport, relay handling, and connection management required for peer-to-peer networking.iroh-blobsimplements content-addressed storage using BLAKE3 hashes, transmitting data over QUIC streams opened through the core endpoint.iroh-gossipoffers topic-based message dissemination by registering protocol handlers with the shared endpoint.iroh-docscomposes blobs and gossip to provide eventually-consistent document storage without implementing its own transport layer.- Applications typically bind a single
Endpointand 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, 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →