What Is the iroh API? A Complete Guide to Peer-to-Peer Networking in Rust

The iroh API is a Rust library that provides a high-level, peer-to-peer networking stack built on QUIC, abstracting away hole-punching, relay fallback, address discovery, and TLS-based authentication behind ergonomic types like Endpoint and Builder.

The iroh API serves as the public interface for the n0-computer/iroh repository, enabling Rust applications to establish secure, direct connections between devices across the internet without manual firewall configuration or complex infrastructure management. It exposes a concise set of methods that handle the underlying complexities of modern peer-to-peer communication while maintaining type safety and performance.

Core Concepts of the iroh API

Endpoint

The Endpoint is the central object representing a local iroh node. According to the source code in iroh/src/lib.rs (lines 82-86), it owns the cryptographic key pair, manages socket bindings, handles address lookup, and controls the QUIC transport layer. All network operations flow through this type.

Builder Pattern

Configuration follows a fluent Builder API defined in iroh/src/endpoint.rs (lines 22-30). This pattern allows you to set secret keys, ALPN protocols, relay modes, and custom transports before calling bind() to initialize the endpoint.

Identity and Authentication

Each node is identified by an EndpointId (also referred to as PublicKey), which represents the public portion of the node's secret key. As documented in iroh/src/lib.rs (lines 84-90), this identifier serves as both the network identity and the basis for TLS authentication, eliminating the need for traditional certificate authorities.

Relay Infrastructure

When direct connectivity fails, the API falls back to RelayUrl endpoints. The default configuration uses the "number 0" relay (see iroh/src/lib.rs lines 96-103), though custom relays can be specified via the builder to handle traffic forwarding when direct paths are unavailable.

Address Lookup Services

The API supports optional address discovery mechanisms like DNS-based PKARR, documented in iroh/src/lib.rs (lines 60-70). These services publish an EndpointId alongside reachable addresses, allowing peers to connect using only the cryptographic identifier without knowing IP addresses beforehand.

QUIC Streams

Once connected, applications communicate through lightweight QUIC streams. The stream API in iroh/src/lib.rs (lines 36-44) provides bidirectional (open_bi) and unidirectional (open_uni) variants that are inexpensive to create and can be multiplexed arbitrarily over a single connection.

How the iroh API Establishes Connections

The connection process implemented in the iroh API follows a specific sequence that combines multiple networking techniques:

  1. Endpoint Construction – Calling Endpoint::builder(preset).bind().await creates a Builder, applies a configuration preset (e.g., presets::N0), and binds sockets plus QUIC configuration. The logic in Builder::bind (iroh/src/endpoint.rs lines 24-30) generates a SecretKey automatically if none is supplied.

  2. Relay Discovery – If a direct address is unknown, the endpoint contacts its home relay (default "number 0" as described in iroh/src/lib.rs lines 97-104). The relay forwards encrypted packets based on the remote EndpointId until a direct path is established.

  3. Hole-Punching – After the initial relay-mediated handshake, both endpoints attempt direct UDP connectivity via hole-punching techniques. As noted in iroh/src/lib.rs (lines 66-73), successful hole-punching causes traffic to switch to the direct path, removing the relay from the data path.

  4. TLS Authentication – Each endpoint authenticates the other by verifying the peer's public key (the EndpointId). According to iroh/src/lib.rs (lines 81-89), no traditional client/server certificates are used; the secret key of each endpoint serves as both identity and TLS key material.

  5. Stream Creation – With the QUIC connection ready, applications open streams via Connection::open_bi or Connection::open_uni. These methods, referenced in iroh/src/lib.rs (lines 36-44), create inexpensive streams that can be opened at any time during the connection lifetime.

Working with the iroh API: Code Examples

Basic Endpoint Workflow

This example demonstrates creating an endpoint, connecting to a remote peer, and exchanging data over a bidirectional stream:

// 1️⃣ Build and bind an endpoint (using the default N0 preset)
let ep = iroh::Endpoint::builder(iroh::endpoint::presets::N0)
    .alpns(vec![b"my-alpn".to_vec()])   // accept this ALPN
    .bind()
    .await?;                            // ← binds sockets, creates QUIC config

// 2️⃣ Connect to a remote peer (you need the remote EndpointId)
let remote_addr = iroh::EndpointAddr::from_parts(
    remote_endpoint_id,                 // the peer’s public key
    None,                              // optional RelayUrl
    vec![]);                           // optional direct IPs
let conn = ep.connect(remote_addr, b"my-alpn").await?;

// 3️⃣ Open a bidirectional stream and exchange data
let (mut send, mut recv) = conn.open_bi().await?;
send.write_all(b"ping").await?;
send.finish()?;                       // finish sending side
let reply = recv.read_to_end(64).await?;
assert_eq!(&reply, b"pong");

// 4️⃣ Gracefully shut down
conn.close(0u32.into(), b"bye");
ep.close().await;

Address Lookup with PKARR

This example shows how to enable DNS-based address discovery, allowing peers to find each other without sharing IP addresses:

use iroh::endpoint::presets::N0;
use iroh::address_lookup::DnsAddressLookup;

// Build an endpoint that publishes its ID via DNS (pkarr) and discovers peers
let ep = iroh::Endpoint::builder(N0)
    .address_lookup(DnsAddressLookup::default()) // enable DNS-based lookup
    .bind()
    .await?;

The address_lookup service publishes the endpoint's EndpointId together with any discovered external addresses, allowing other peers to dial using only the cryptographic identifier.

Key Source Files in the iroh API

Understanding the repository structure helps when navigating the iroh API implementation:

  • iroh/src/lib.rs – Re-exports the public API (Endpoint, RelayUrl, etc.) and contains the high-level documentation describing architecture and usage patterns.
  • iroh/src/endpoint.rs – Implementation of Endpoint, its Builder, connection logic, and public methods including connect, accept, and add_external_addr.
  • iroh/src/socket/*.rs – Low-level transport and path-selection code handling IP transports, relay transports, and custom transport implementations.
  • iroh-base/src/lib.rs – Core types including EndpointId, PublicKey, SecretKey, and RelayUrl.
  • iroh-dns/src/lib.rs – DNS resolver used for relay hostnames and PKARR address lookup services.
  • iroh-relay/src/* – Relay server and client implementation that forwards encrypted traffic when direct connectivity fails.

Summary

  • The iroh API provides a Rust-native interface for peer-to-peer networking over QUIC, exposing high-level abstractions like Endpoint and Builder.
  • Identity is cryptographic: Nodes use EndpointId (public keys) for both addressing and TLS authentication, eliminating certificate management overhead.
  • Automatic connectivity: The API handles complex network traversal via relay fallback (RelayUrl) and automatic hole-punching, as implemented in iroh/src/lib.rs lines 66-104.
  • Ergonomic configuration: The Builder pattern in iroh/src/endpoint.rs enables fluent setup of ALPN protocols, relay modes, and address lookup services.
  • Lightweight streams: QUIC streams are inexpensive to create and multiplex, accessible via Connection::open_bi and Connection::open_uni.

Frequently Asked Questions

What transport protocol does the iroh API use?

The iroh API uses QUIC as its underlying transport protocol, providing built-in encryption, multiplexing, and congestion control. This is implemented through the Endpoint type in iroh/src/lib.rs, which manages the QUIC configuration and socket bindings.

How does the iroh API handle devices behind NAT or firewalls?

The iroh API automatically handles NAT traversal through a combination of relay fallback and hole-punching. When direct connectivity fails, traffic routes through a default or custom RelayUrl (as documented in iroh/src/lib.rs lines 96-103). Simultaneously, both endpoints attempt UDP hole-punching to establish a direct path, switching traffic away from the relay once successful.

What is the relationship between EndpointId and TLS certificates?

In the iroh API, the EndpointId (a public key) serves as the TLS identity. According to iroh/src/lib.rs (lines 81-89), each endpoint uses its secret key to generate TLS key material during the handshake. Peers authenticate each other by verifying that the presented public key matches the expected EndpointId, eliminating the need for traditional X.509 certificate chains.

Can I use custom relay servers with the iroh API?

Yes, the iroh API supports custom relay servers. While the default preset uses the "number 0" relay, you can configure alternative RelayUrl endpoints through the Builder API in iroh/src/endpoint.rs. This allows deployment of private relay infrastructure or selection of geographically closer relay nodes.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →