# Key Modules in the iroh Codebase: A Guide to the P2P Networking Stack

> Explore the key modules in the iroh codebase to understand its P2P networking stack. Discover the Rust crates that power iroh's decentralized communication.

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

---

**The iroh codebase organizes its functionality into six distinct Rust crates—`iroh`, `iroh-base`, `iroh-relay`, `iroh-dns`, `iroh-dns-server`, and `iroh-bench`—that collectively provide a complete peer-to-peer networking stack built on QUIC.**

The iroh project is structured as a Rust workspace where each crate exposes a focused set of responsibilities. Understanding these key modules is essential for developers integrating peer-to-peer capabilities, as the separation allows for selective dependency inclusion and clear API boundaries. The architecture handles everything from cryptographic identity and address lookup to relay-assisted hole-punching and performance benchmarking.

## The Six Core Modules

The repository at `n0-computer/iroh` divides its functionality into the following workspace members, each defined in the root [`Cargo.toml`](https://github.com/n0-computer/iroh/blob/main/Cargo.toml):

| Module | Purpose | Primary Source |
| --- | --- | --- |
| **iroh** | Supplies the public API (`Endpoint`, `RelayMode`) and orchestrates high‑level P2P workflows including connection establishment, stream handling, and relay usage. | [`iroh/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs) |
| **iroh-base** | Defines core identity and addressing types (`EndpointId`, `PublicKey`, `SecretKey`, `RelayUrl`, `EndpointAddr`, `TransportAddr`) shared across all crates. | [`iroh-base/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/lib.rs) |
| **iroh-relay** | Implements the DERP‑style relay protocol with both server and client libraries, plus associated TLS utilities for NAT traversal. | [`iroh-relay/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/lib.rs) |
| **iroh-dns** | Handles DNS‑based endpoint discovery using the PKARR packet format, publishing and resolving relay and direct addresses as DNS TXT records. | [`iroh-dns/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/lib.rs) |
| **iroh-dns-server** | Provides a minimal in‑memory DNS server for storing endpoint records, useful for local testing or private deployments. | [`iroh-dns-server/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns-server/src/lib.rs) |
| **iroh-bench** | Contains benchmarking utilities for throughput and latency tests that exercise the QUIC stack, relay protocol, and address‑lookup service. | [`iroh/bench/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/bench/src/lib.rs) |

## Module Architecture and Data Flow

The crates interact through a specific sequence to establish peer-to-peer connections. This architecture ensures that cryptographic identity is centralized while networking concerns remain modular.

1. **Endpoint Creation** – Applications construct an `Endpoint` via the **iroh** crate. This struct internally holds a `SecretKey` from **iroh-base** that identifies the node and secures TLS handshakes.

2. **Address Lookup** – When connecting to a peer, the endpoint queries `DnsAddressLookup` from **iroh-dns** to retrieve the peer’s `RelayUrl` and direct `TransportAddr`s, using the peer’s `EndpointId` as the lookup key.

3. **Relay Interaction** – If direct paths fail, the endpoint contacts a relay server via **iroh-relay** client utilities. The relay forwards encrypted packets until hole‑punching establishes a direct connection.

4. **Connection Management** – After QUIC handshake completion, the `Endpoint` exposes `Connection` objects supporting uni‑directional and bi‑directional streams. These streams are cheap, multiplexed, and created on‑the‑fly.

5. **Metrics and Diagnostics** – The **iroh** crate re‑exports metrics and runtime reporting utilities, allowing monitoring of connection health and relay latency.

6. **Testing** – The **iroh-bench** crate validates performance at each layer, ensuring relay throughput and DNS resolution meet requirements.

## Practical Implementation Examples

### Creating Endpoints with the iroh Crate

The primary entry point for applications is the `Endpoint` struct, which coordinates keys, relays, and connections. Below, the endpoint uses the default "number 0" relay preset and connects to a peer using internally managed **iroh-relay** and **iroh-base** types:

```rust
use iroh::{Endpoint, endpoint::presets};
use n0_error::Result;

#[tokio::main]
async fn main() -> Result<()> {
    // The Endpoint holds its own secret key (iroh-base) and performs TLS handshakes.
    let ep = Endpoint::bind(presets::N0).await?;        // ← iroh::Endpoint
    // Obtain a peer’s address (could be from DNS or a config file).
    let peer_addr = "example-endpoint-id".parse()?;    // ← iroh-base::EndpointId
    // Connect via the relay (iroh-relay client is used internally).
    let conn = ep.connect(peer_addr, b"my-alpn").await?; // ← iroh::Endpoint::connect
    // Open a bi-directional stream and exchange data.
    let (mut send, mut recv) = conn.open_bi().await?;
    send.write_all(b"hello").await?;
    send.finish().await?;
    let mut buf = vec![];
    recv.read_to_end(&mut buf).await?;
    println!("Received: {:?}", String::from_utf8_lossy(&buf));
    // Gracefully shut down.
    conn.close(0u8.into(), b"done");
    ep.close().await;
    Ok(())
}

```

### DNS-Based Discovery with iroh-dns

For scenarios requiring explicit address resolution, the **iroh-dns** crate exposes `DnsAddressLookup` to resolve `EndpointId`s to connection parameters:

```rust
use iroh::address_lookup::DnsAddressLookup;
use iroh::EndpointId;

#[tokio::main]
async fn lookup_example() -> Result<()> {
    let lookup = DnsAddressLookup::default();                 // ← iroh-dns
    let endpoint_id = EndpointId::from_hex("deadbeef…")?;
    let address = lookup.lookup(endpoint_id).await?;          // Returns RelayUrl + direct addresses
    println!("Discovered relay: {}", address.relay_url);
    Ok(())
}

```

### Running a Custom Relay Server

The **iroh-relay** crate provides server capabilities for hosting private relay infrastructure. This is the binary implementation used when running `iroh-relay`:

```rust
use iroh_relay::server::RelayServer;
use std::net::SocketAddr;

#[tokio::main]
async fn start_relay() -> Result<()> {
    let bind_addr: SocketAddr = "0.0.0.0:4000".parse()?;
    let server = RelayServer::bind(bind_addr).await?;
    println!("Relay listening on {}", bind_addr);
    server.run().await?;
    Ok(())
}

```

## Entry Points and Source Files

When navigating the repository, these files represent the primary entry points for each module:

- **[`iroh/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs)** – Defines the `Endpoint` struct, connection handling logic, and re‑exports core types for the public API.
- **[`iroh-base/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/lib.rs)** – Central definitions for cryptographic primitives (`SecretKey`, `PublicKey`) and addressing types (`EndpointId`, `RelayUrl`).
- **[`iroh-relay/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/lib.rs)** – Implements the `RelayServer` and client components for the DERP protocol.
- **[`iroh-dns/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/lib.rs)** – Provides `DnsAddressLookup` and PKARR packet handling for decentralized discovery.
- **[`iroh-dns-server/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns-server/src/lib.rs)** – Minimal DNS server implementation for local endpoint publishing.
- **[`iroh/bench/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/bench/src/lib.rs)** – Performance harnesses for validating stream throughput and relay latency.
- **[`Cargo.toml`](https://github.com/n0-computer/iroh/blob/main/Cargo.toml)** (root) – Coordinates workspace members and ensures feature flags propagate consistently across the networking stack.

## Summary

- The **iroh** crate provides the high‑level `Endpoint` API that orchestrates connections, while **iroh-base** supplies the underlying cryptographic identities and address types.
- **iroh-relay** implements the DERP-style relay protocol for NAT traversal, available as both client library and server binary.
- **iroh-dns** enables PKARR-based discovery through DNS TXT records, complemented by **iroh-dns-server** for private testing environments.
- **iroh-bench** supplies performance testing utilities to validate the QUIC stack and relay throughput.
- All modules share a unified versioning scheme and feature flag system defined in the workspace root, ensuring consistent API compatibility across the peer-to-peer networking stack.

## Frequently Asked Questions

### What is the difference between the iroh and iroh-base crates?

The **iroh** crate contains the high‑level public API, including the `Endpoint` struct and connection management logic, while **iroh-base** defines the low‑level primitives such as `SecretKey`, `PublicKey`, and `EndpointId` that are shared across all workspace members. Applications typically depend on **iroh**, which re‑exports necessary types from **iroh-base** internally.

### When should I use iroh-dns versus iroh-dns-server?

Use **iroh-dns** when your application needs to resolve or publish endpoint addresses using the PKARR protocol against existing DNS infrastructure. Use **iroh-dns-server** when you need to run a standalone, in‑memory DNS server for local development, testing, or private networks that do not rely on public DNS resolvers.

### How does iroh-relay integrate with the main iroh crate?

The **iroh** crate internally uses **iroh-relay** client utilities when an `Endpoint` cannot establish a direct connection to a peer. When you call `Endpoint::connect`, the library automatically contacts relay servers (specified via `RelayUrl` from address lookup) to forward encrypted packets until hole‑punching succeeds, after which traffic migrates to direct paths. This integration is transparent to the application developer.

### Why are the modules organized as separate crates rather than a single library?

The modular architecture allows developers to depend only on the functionality they need—such as importing **iroh-base** for cryptographic types without pulling in relay or DNS logic. This separation also enforces clean API boundaries, enables independent versioning of stable components, and facilitates targeted testing and benchmarking via **iroh-bench** without affecting the core library.