# How to Integrate iroh into an Existing Application: A Complete Guide

> Integrate iroh into an existing application by building an endpoint with ALPN and relay configurations. Learn how iroh's QUIC stack handles NAT and peer-to-peer connections automatically.

- Repository: [number zero/iroh](https://github.com/n0-computer/iroh)
- Tags: how-to-guide
- Published: 2026-06-23

---

**You integrate iroh into an existing application by creating an `Endpoint` using the `Builder` API, configuring ALPN protocols and relay settings, and binding to spawn the QUIC networking stack that handles NAT traversal and peer-to-peer connections automatically.**

The `iroh` crate from the [n0-computer/iroh](https://github.com/n0-computer/iroh) repository provides a Rust library that embeds a full-featured QUIC-based peer-to-peer networking stack into any application. By leveraging the `Endpoint` abstraction, you can add decentralized connectivity, NAT traversal, and end-to-end encryption without managing complex network internals.

## Core Architecture of iroh

Understanding the primary components in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) helps you integrate the library effectively:

- **`Endpoint`** – The public API that owns your cryptographic identity, manages UDP sockets, and exposes methods for dialing and accepting connections.
- **`Builder`** – Configures the endpoint before binding, handling secret keys, ALPN protocols, transport settings, and relay maps.
- **`RelayMap`** – Stores relay server URLs that facilitate NAT traversal when direct connections fail.
- **Address Lookup** – Services like the built-in **Pkarr** DNS that publish and resolve public addresses.
- **`Connection`** – Represents a QUIC connection to a remote peer, providing bidirectional and unidirectional streams.
- **`Router`** – Optional dispatcher that routes inbound streams to protocol handlers based on ALPN identifiers.

## Step-by-Step Integration Process

### Add the Dependency

Include iroh in your [`Cargo.toml`](https://github.com/n0-computer/iroh/blob/main/Cargo.toml):

```toml
[dependencies]
iroh = "0.x"
tokio = { version = "1", features = ["full"] }

```

### Configure the Endpoint Builder

Create a `Builder` using a preset configuration, then customize it with your application's protocols:

```rust
use iroh::Endpoint;

let endpoint = Endpoint::builder(presets::N0)  // Use N0 preset for DNS and relay defaults
    .alpns(vec![b"my-app/1.0".to_vec()])       // Register your ALPN protocol
    .relay_mode(RelayMode::Default)            // Use default relay servers
    .bind()
    .await?;

```

The `presets::N0` module (defined in [`iroh/src/presets.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/presets.rs)) bundles sensible defaults including Pkarr address lookup and the number 0 relay cluster.

### Bind and Initialize

Calling `bind().await` spawns the QUIC server, creates UDP sockets, contacts relay servers, and publishes your address. After binding, call `online().await` to ensure NAT traversal is ready:

```rust
endpoint.online().await?;
let my_addr = endpoint.addr();  // Share this with peers

```

### Accept and Dial Connections

Use the `Router` to handle inbound protocols automatically, or manage connections directly:

```rust
// Accept connections manually
while let Some(conn) = endpoint.accept().await {
    let connection = conn.await?;
    handle_connection(connection).await;
}

// Or dial a remote peer
let conn = endpoint.connect(remote_addr, b"my-app/1.0").await?;

```

## Practical Implementation Examples

### Basic Echo Server and Client

This complete example demonstrates a server that accepts connections and echoes data back, plus a client that connects and sends a message:

```rust
use iroh::{
    Endpoint,
    endpoint::{presets, Connection, Router},
    protocol::{AcceptError, ProtocolHandler},
};

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

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Server side
    let server_ep = Endpoint::builder(presets::N0)
        .alpns(vec![ALPN.to_vec()])
        .bind()
        .await?;

    let router = Router::builder(server_ep.clone())
        .accept(ALPN, Echo)
        .spawn();

    server_ep.online().await;

    // Client side
    let client_ep = Endpoint::builder(presets::N0).bind().await?;
    let remote_addr = server_ep.addr();
    
    let conn = client_ep.connect(remote_addr, ALPN).await?;
    let (mut send, mut recv) = conn.open_bi().await?;
    send.write_all(b"Hello, iroh!").await?;
    send.finish()?;
    
    let reply = recv.read_to_end(1024).await?;
    assert_eq!(&reply, b"Hello, iroh!");

    // Cleanup
    router.shutdown().await?;
    client_ep.close().await;
    server_ep.close().await;
    Ok(())
}

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

```

### Configuring Custom Relays

To use your own relay infrastructure instead of the defaults, configure a custom `RelayMap` as implemented in [`iroh-base/src/relay_url.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/relay_url.rs):

```rust
use iroh::{
    Endpoint,
    endpoint::{presets, RelayMode},
    iroh_relay::RelayConfig,
    iroh_base::RelayUrl,
};

let custom_relay = RelayUrl::parse("https://my-relay.example.com/")?;
let relay_cfg = RelayConfig::default();

let ep = Endpoint::builder(presets::N0)
    .relay_mode(RelayMode::Custom(vec![(custom_relay, relay_cfg)]))
    .bind()
    .await?;

```

### Implementing Custom Transports

For advanced use cases requiring custom network transports, enable the unstable feature and implement the `CustomTransport` trait:

```toml
[dependencies]
iroh = { version = "0.x", features = ["unstable-custom-transports"] }

```

```rust
use std::sync::Arc;
use iroh::{
    Endpoint,
    endpoint::{presets, transports::CustomTransport},
};

struct MyTransport;
impl CustomTransport for MyTransport {
    // Implement required methods per iroh/src/socket/transports/custom.rs
}

let ep = Endpoint::builder(presets::N0)
    .add_custom_transport(Arc::new(MyTransport))
    .bind()
    .await?;

```

## Key Source Files Reference

Referencing these specific files in the n0-computer/iroh repository helps you understand implementation details:

- **[`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs)** – Contains the `Endpoint` struct, `Builder` implementation (starting around line 22), and connection logic.
- **[`iroh-base/src/relay_url.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/relay_url.rs)** – Defines `RelayUrl` and `RelayMap` types for relay configuration.
- **[`iroh/src/address_lookup.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup.rs)** – Implements `AddressLookupBuilder` and the Pkarr DNS service.
- **[`iroh/src/socket.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket.rs)** – Low-level UDP socket handling and QUIC integration.
- **[`iroh/examples/echo.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/echo.rs)** – Full-featured echo example referenced in the repository README.

## Summary

- **The `Endpoint`** is the primary abstraction for managing peer-to-peer connections in iroh, handling cryptographic identities and NAT traversal automatically.
- **Use `Endpoint::builder(presets::N0)`** to quickly configure a new endpoint with sensible defaults for relays and address lookup.
- **Configure ALPN protocols** via the `alpns` method to register which protocols your application supports.
- **The `Router`** simplifies inbound connection handling by dispatching streams to protocol handlers based on ALPN identifiers.
- **All connections are end-to-end encrypted** using QUIC, requiring no additional TLS configuration for peer-to-peer security.

## Frequently Asked Questions

### Can iroh integrate with existing async Rust applications?

Yes, iroh is built on Tokio and integrates seamlessly with existing async Rust code. The `Endpoint` methods like `bind()`, `connect()`, and `accept()` are async and can be used within your existing runtime without blocking.

### Does iroh require a specific relay server to function?

No, while iroh provides default relay servers through the `N0` preset, you can configure custom relays using `RelayMode::Custom` with your own `RelayUrl` endpoints. The system will attempt direct connections first, falling back to relays only when necessary for NAT traversal.

### How do I handle protocol versioning in iroh?

Implement protocol versioning through ALPN strings. Register multiple versions using the `alpns` method on the `Builder`, or use the `Router` to dispatch different versions to different `ProtocolHandler` implementations based on the ALPN identifier received during connection establishment.

### Is the custom transport API stable for production use?

No, the custom transport API is currently unstable and requires the `unstable-custom-transports` feature flag. For production applications, use the standard UDP transport configured automatically by the `Builder` until the custom transport interface stabilizes in future releases.