# How to Get Started with Iroh Examples: A Complete Guide for Beginners

> Start with Iroh examples by cloning the n0-computer/iroh repo and running echo, blob transfer, or gossip examples with cargo run to learn core peer-to-peer QUIC APIs.

- Repository: [number zero/iroh](https://github.com/n0-computer/iroh)
- Tags: getting-started
- Published: 2026-07-06

---

**To get started with Iroh examples, clone the n0-computer/iroh repository and run the echo, blob transfer, or gossip examples using `cargo run -p iroh --example <name>`, which demonstrate the core `Endpoint` and `Router` APIs for peer-to-peer QUIC connections.**

Iroh is a Rust-first library that enables applications to dial peers by public key, automatically selecting the fastest path through direct connections, hole-punching, or public relays. This guide covers the essential beginner examples from the n0-computer/iroh repository, showing you how to establish connections, transfer content-addressed data, and build publish-subscribe networks.

## Prerequisites and Repository Setup

Before running the examples, ensure you have Rust installed. Clone the repository and explore the available crates:

```bash
git clone https://github.com/n0-computer/iroh.git
cd iroh

```

The repository contains several key crates:

- **`iroh`** – Core library with `Endpoint` and connection establishment logic ([[`iroh/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs)](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs))
- **`iroh-relay`** – Relay server for NAT traversal ([[`iroh-relay/src/main.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/main.rs)](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/main.rs))
- **`iroh-blobs`** – Content-addressed blob storage and transfer
- **`iroh-gossip`** – Scalable publish-subscribe overlay network

## Example 1: Simple Echo Protocol

The echo example demonstrates the fundamental pattern of connecting two peers over QUIC using Application-Layer Protocol Negotiation (ALPN). This example uses the `Endpoint` type from [[`iroh/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs)](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs) to manage connections.

### Client Implementation

Create a client that connects to a remote peer and sends a message:

```rust
use iroh::Endpoint;
use anyhow::Result;
use tokio::io::{AsyncWriteExt, AsyncReadExt};

const ALPN: &[u8] = b"iroh-example/echo/0";

#[tokio::main]
async fn main() -> Result<()> {
    // Bind a local endpoint that manages connections
    let endpoint = Endpoint::bind().await?;
    
    // Connect to a remote peer using their address
    let addr = "...remote endpoint address...".parse()?;
    let conn = endpoint.connect(addr, ALPN).await?;
    
    // Open a bidirectional QUIC stream
    let (mut send, mut recv) = conn.open_bi().await?;
    
    // Send payload and read response
    send.write_all(b"Hello, iroh!").await?;
    send.finish()?;
    let mut response = Vec::new();
    recv.read_to_end(&mut response).await?;
    
    assert_eq!(response, b"Hello, iroh!");
    
    // Cleanup
    conn.close(0u32.into(), b"bye!");
    endpoint.close().await;
    Ok(())
}

```

The `Endpoint::bind()` method creates a local endpoint that owns a QUIC engine, while `connect()` handles DNS resolution, hole-punching, and relay fallback automatically.

### Server Implementation

The server side implements the `ProtocolHandler` trait to accept incoming connections:

```rust
use iroh::Endpoint;
use iroh::protocol::ProtocolHandler;
use iroh::connection::Connection;
use anyhow::Result;
use std::sync::Arc;

const ALPN: &[u8] = b"iroh-example/echo/0";

#[derive(Debug, Clone)]
struct Echo;

#[async_trait::async_trait]
impl ProtocolHandler for Echo {
    async fn accept(&self, conn: Connection) -> Result<()> {
        let (mut send, mut recv) = conn.accept_bi().await?;
        tokio::io::copy(&mut recv, &mut send).await?;
        send.finish()?;
        conn.closed().await;
        Ok(())
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    let endpoint = Endpoint::bind().await?;
    let router = Router::builder(endpoint)
        .accept(ALPN.to_vec(), Arc::new(Echo))
        .spawn()
        .await?;
    // Router runs indefinitely
    Ok(())
}

```

The `Router::builder` registers protocol handlers by ALPN identifier, allowing the same endpoint to serve multiple protocols.

## Example 2: Blob Transfer with iroh-blobs

For transferring large files, `iroh-blobs` provides a content-addressed store using BLAKE3 hashes. This example demonstrates the high-level API similar to the echo pattern but with persistent storage.

```rust
use iroh::Endpoint;
use iroh_blobs::BlobStore;
use anyhow::Result;
use std::path::PathBuf;

const ALPN: &[u8] = b"iroh-blobs/transfer/0";

#[tokio::main]
async fn main() -> Result<()> {
    // Initialize endpoint and on-disk blob store
    let endpoint = Endpoint::bind().await?;
    let store = BlobStore::open(PathBuf::from("./my_blobs")).await?;
    
    // Sender: Add file to store and transmit
    let cid = store.add_file("large_file.dat").await?;
    let conn = endpoint.connect(remote_addr, ALPN).await?;
    store.send(&conn, cid).await?;
    
    // Receiver: Accept connections and automatically store blobs
    let router = Router::builder(endpoint)
        .accept(ALPN.to_vec(), Arc::new(store.clone()))
        .spawn()
        .await?;
    Ok(())
}

```

Key implementation files include [[`iroh-blobs/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-blobs/src/lib.rs)](https://github.com/n0-computer/iroh/blob/main/iroh-blobs/src/lib.rs) for the core store and [`iroh-blobs/examples/transfer.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-blobs/examples/transfer.rs) for the complete runnable demo.

## Example 3: Publish-Subscribe with iroh-gossip

The gossip protocol builds a scalable overlay network on top of Iroh's connection layer, enabling message broadcasting to multiple peers.

### Publisher Implementation

Create a publisher that sends messages to a topic:

```rust
use iroh::Endpoint;
use iroh_gossip::{Gossip, Topic};
use anyhow::Result;
use std::sync::Arc;

#[tokio::main]
async fn main() -> Result<()> {
    let endpoint = Endpoint::bind().await?;
    let gossip = Gossip::new(endpoint.clone()).await?;
    
    // Create topic from arbitrary bytes
    let topic = Topic::from(b"chat-room-1".as_ref());
    
    // Publish messages periodically
    let mut interval = tokio::time::interval(std::time::Duration::from_secs(1));
    loop {
        interval.tick().await;
        let msg = format!("ping at {}", chrono::Utc::now());
        gossip.publish(&topic, msg.into_bytes()).await?;
    }
}

```

### Subscriber Implementation

Subscribers register callbacks to receive messages:

```rust
use iroh::Endpoint;
use iroh_gossip::{Gossip, Topic, Message};
use anyhow::Result;

#[tokio::main]
async fn main() -> Result<()> {
    let endpoint = Endpoint::bind().await?;
    let gossip = Gossip::new(endpoint.clone()).await?;
    let topic = Topic::from(b"chat-room-1".as_ref());
    
    gossip.subscribe(&topic, |msg: Message| async move {
        println!("Got: {}", String::from_utf8_lossy(&msg.payload));
    }).await?;
    
    // Keep alive indefinitely
    futures::future::pending::<()>().await;
    Ok(())
}

```

The high-level API is defined in [[`iroh-gossip/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-gossip/src/lib.rs)](https://github.com/n0-computer/iroh/blob/main/iroh-gossip/src/lib.rs), with a complete example available at [`iroh-gossip/examples/pubsub.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-gossip/examples/pubsub.rs).

## Running a Local Relay (Optional)

For testing NAT traversal without depending on public infrastructure, run a local relay server:

```bash
cargo run -p iroh-relay -- --listen 0.0.0.0:2345 --cert ./cert.pem --key ./key.pem

```

The relay server implementation resides in [[`iroh-relay/src/main.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/main.rs)](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/main.rs), which parses CLI options and starts the QUIC listener, while [[`iroh-relay/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/lib.rs)](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/lib.rs) contains the core client handling and connection pooling logic.

## Key Source Files and Architecture

Understanding the repository structure helps when extending these examples:

- **[[`iroh/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs)](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs)** – Public API exposing `Endpoint`, `Router`, and protocol registration
- **[[`iroh-base/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/lib.rs)](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/lib.rs)** – Core data structures including `EndpointId` and `RelayUrl`
- **[[`iroh-base/src/key.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/key.rs)](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/key.rs)** – Public-key utilities and DER/PEM parsing
- **[[`iroh-dns-server/src/main.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns-server/src/main.rs)](https://github.com/n0-computer/iroh/blob/main/iroh-dns-server/src/main.rs)** – DNS/PKARR server for resolving `EndpointId` to addresses
- **[[`iroh-dns/src/dns.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/dns.rs)](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/dns.rs)** – DNS resolver client used by `Endpoint` during peer lookup

## Summary

- **Clone the repository** from n0-computer/iroh to access official examples and source code
- **Start with the echo example** to understand `Endpoint::bind()`, `connect()`, and the `ProtocolHandler` trait
- **Use iroh-blobs** for content-addressed file transfer with automatic deduplication via BLAKE3 hashing
- **Implement gossip protocols** using `iroh-gossip` for scalable publish-subscribe messaging over the same QUIC backbone
- **Test locally** with `iroh-relay` to understand NAT traversal without external dependencies

## Frequently Asked Questions

### How do I run the Iroh examples without cloning the entire repository?

You can add the specific crates as dependencies in your [`Cargo.toml`](https://github.com/n0-computer/iroh/blob/main/Cargo.toml) and copy the example code from the repository's `examples/` directories. For instance, add `iroh = "0.7"` and `iroh-blobs = "0.7"` to your dependencies, then adapt the code from [`iroh-blobs/examples/transfer.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-blobs/examples/transfer.rs) to your project structure.

### What is the difference between Endpoint and Router in Iroh?

The **`Endpoint`** struct, defined in [[`iroh/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs)](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs), manages the underlying QUIC connections and dialing logic. The **`Router`** allows you to register multiple `ProtocolHandler` implementations by ALPN identifier, enabling a single endpoint to serve different protocols simultaneously without manual connection dispatch.

### Do I need to run my own relay server to use Iroh?

No, Iroh includes default public relays that handle NAT traversal automatically. However, for private deployments or testing offline scenarios, you can run your own relay using the `iroh-relay` crate by executing `cargo run -p iroh-relay` with appropriate certificate and listen address parameters.

### Which Iroh example should I start with as a beginner?

Begin with the **echo example** because it demonstrates the fundamental connection lifecycle: binding an endpoint, connecting by address, opening bidirectional streams, and graceful shutdown. Once you understand this pattern, the blob transfer and gossip examples build upon the same `Endpoint` and `Router` APIs with additional protocol-specific logic.