# Exploring Iroh's Capabilities with Examples: Building Peer-to-Peer Applications in Rust

> Learn Rust peer-to-peer networking with Iroh. Explore examples of building custom protocols with hole-punching, relay fallback, and QUIC transport easily.

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

---

**Iroh provides a Rust-based peer-to-peer networking stack that abstracts hole-punching, relay fallback, and QUIC transport configuration, enabling developers to implement custom protocols using the `Endpoint` and `ProtocolHandler` patterns demonstrated in the official examples.**

Iroh is a Rust library developed by n0-computer that simplifies direct peer-to-peer communication by handling network traversal complexities automatically. When exploring Iroh's capabilities with examples, you'll discover an architecture built around the `Endpoint` abstraction, which manages cryptographic identities, connection state, and pluggable transports. The library exposes high-level APIs in [`iroh/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs) while allowing fine-grained control over relay servers, address lookup, and custom protocol handlers.

## Core Architecture and Networking Concepts

The Iroh networking model centers on the **Endpoint**, defined in the crate root at [`iroh/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs), which serves as the central object for creating, tracking, and accepting connections. Each endpoint is identified by an **EndpointId**—a public key that functions as both the node identifier and the TLS authentication credential for all QUIC connections.

**Relay servers** provide always-available forwarding nodes for encrypted traffic when direct connectivity fails, with the library defaulting to public "number 0" relays via `RelayMode::Default`. After establishing an initial connection through a relay, Iroh attempts **hole punching** to negotiate a direct path, falling back to relayed mode only when necessary. For address resolution, optional services in `iroh/src/address_lookup` implement DNS and PKARR discovery, allowing clients to connect using only an `EndpointId` rather than hardcoded IP addresses.

The transport layer builds on the **noq** QUIC implementation, providing TLS encryption, stream multiplexing, and datagram support. Configuration occurs through `QuicTransportConfig`, implemented in [`iroh/src/endpoint/quic.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/quic.rs), which exposes parameters for window sizing, congestion control, and TLS settings.

### The Standard API Flow

Working with Iroh follows a consistent five-step pattern:

1. **Create an endpoint** using `Endpoint::bind(presets::N0).await?`, which configures a default node with home relay and ALPN support.
2. **Connect** to peers via `endpoint.connect(addr, alpn).await?`, returning a `Connection` handle.
3. **Open streams** using `open_uni`/`accept_uni` for one-way traffic or `open_bi`/`accept_bi` for bidirectional communication.
4. **Exchange data** across cheap, concurrent streams that do not block each other.
5. **Close gracefully** with `connection.close(code, reason)` for individual connections or `endpoint.close().await` for shutdown.

## Practical Iroh Examples

### Building a Simple Echo Protocol

The [`iroh/examples/echo.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/echo.rs) file demonstrates a minimal bidirectional echo service implementing the `ProtocolHandler` trait. This pattern registers handlers with a `Router` that dispatches connections based on the Application-Layer Protocol Negotiation (ALPN) identifier.

The implementation follows these steps:

- **Bind the endpoint** using `let endpoint = Endpoint::bind(presets::N0).await?;` to create a node with default relay and transport configuration.
- **Build the router** with `Router::builder(endpoint).accept(ALPN, Echo).spawn();`, registering the `Echo` handler for the ALPN byte string `b"iroh-example/echo/0"`.
- **Implement the handler** by defining `impl ProtocolHandler for Echo { async fn accept(&self, connection: Connection) -> Result<(), AcceptError> { ... } }`, which accepts bidirectional streams, copies received bytes back to the sender, and closes the connection.
- **Connect from client** side using `let conn = endpoint.connect(addr, ALPN).await?;`.
- **Send and receive** data through `send.write_all(b"Hello, world!").await?;` and `recv.read_to_end(1000).await?;`, demonstrating a complete round-trip.

### Performance Benchmarking with Transfer

For sophisticated connection handling and transport tuning, [`iroh/examples/transfer.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/transfer.rs) provides a comprehensive reference. This example accepts CLI arguments via `clap` to select modes (Upload, Download, Bidi, Ping) and configure relay URLs, DNS settings, and mDNS discovery.

The example leverages `EndpointArgs::bind_endpoint` from [`iroh/src/endpoint/bind.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/bind.rs) to assemble endpoint builders based on runtime flags, configuring relay modes, address lookup services, and TLS parameters. The `fetch` function connects to a remote `EndpointAddr`, spawns a background path watcher using `spawn_path_watcher`, and executes requests via `perform_request`.

Data flows through `send_data` for uploads or `drain_stream` for downloads, with both functions capturing detailed statistics including bytes transferred, duration, and time-to-first-byte. This example is essential for understanding how to manipulate transport parameters such as receive windows via `builder.transport_config(cfg.build())`.

### Implementing Custom Transports

Iroh supports pluggable transport layers through the `Transport` trait, demonstrated in [`iroh/examples/custom-transport.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/custom-transport.rs). Developers can implement this trait—defined in [`iroh/src/socket/transports/custom.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket/transports/custom.rs)—and register custom implementations via `builder.add_transport(custom)`.

This capability enables experimentation with alternative network stacks, such as unreliable UDP or specialized hardware interfaces, while retaining Iroh's connection management, address discovery, and cryptographic authentication.

## Key Implementation Files

Understanding Iroh's internals requires familiarity with these critical source locations:

- **[`iroh/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs)** – Crate root re-exporting the public API and high-level documentation.
- **[`iroh/src/endpoint/bind.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/bind.rs)** – Builder logic for configuring relays, address lookup, TLS, and transport options.
- **[`iroh/src/endpoint/quic.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/quic.rs)** – Low-level QUIC integration with the noq library and TLS configuration.
- **[`iroh/src/protocol.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/protocol.rs)** – Definitions for `ProtocolHandler` and `Router` enabling ALPN-based protocol dispatch.
- **`iroh/src/address_lookup`** – Modules implementing DNS and PKARR address resolution services.
- **[`iroh/examples/echo.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/echo.rs)** – Minimal echo service ideal for protocol prototyping.
- **[`iroh/examples/transfer.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/transfer.rs)** – Full-featured benchmark demonstrating CLI integration and transport tuning.
- **[`iroh/examples/custom-transport.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/custom-transport.rs)** – Template for registering user-defined transport implementations.

## Summary

- **Iroh abstracts peer-to-peer complexity** through the `Endpoint` abstraction, automatically handling hole punching, relay fallback, and QUIC encryption.
- **Protocol handlers** implement the `ProtocolHandler` trait and register with `Router` for clean ALPN-based dispatch, as shown in [`iroh/src/protocol.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/protocol.rs).
- **Three canonical examples** cover basic echo patterns ([`echo.rs`](https://github.com/n0-computer/iroh/blob/main/echo.rs)), performance tuning ([`transfer.rs`](https://github.com/n0-computer/iroh/blob/main/transfer.rs)), and transport extensibility ([`custom-transport.rs`](https://github.com/n0-computer/iroh/blob/main/custom-transport.rs)).
- **Address discovery** is modular, with implementations for DNS and PKARR located in `iroh/src/address_lookup`.
- **Transport configuration** is fine-grained, allowing window size, relay modes, and custom transports via the builder pattern in [`iroh/src/endpoint/bind.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/bind.rs).

## Frequently Asked Questions

### What is the Endpoint in Iroh?

The **Endpoint** is the primary struct exposed in [`iroh/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs) that represents a node on the network. It manages the cryptographic identity (`EndpointId`), handles incoming connections, and provides the `connect` method for dialing remote peers. You initialize it using `Endpoint::bind()` with presets like `presets::N0` for default relay configuration.

### How does Iroh handle connections behind firewalls or NATs?

Iroh uses a combination of **relay servers** and **hole punching**. When direct connectivity fails, traffic routes through publicly available relays (defaulting to number 0 relays). Simultaneously, both peers attempt UDP hole punching to establish a direct path, automatically upgrading the connection when successful while maintaining encrypted QUIC channels throughout.

### Can I implement custom transport protocols with Iroh?

Yes, by implementing the `Transport` trait defined in [`iroh/src/socket/transports/custom.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket/transports/custom.rs) and registering it with the endpoint builder via `add_transport()`. This allows integration of alternative network stacks—such as datagram protocols or specialized hardware interfaces—while retaining Iroh's connection management and `ProtocolHandler` dispatch system.

### Where does Iroh implement address lookup services?

Address resolution resides in the `iroh/src/address_lookup` directory, containing modules for DNS and PKARR (Public Key Address Resolution) services. These allow endpoints to publish their relay URLs and direct addresses under their `EndpointId`, enabling connectivity using only the public key identifier without manual IP configuration.