# What Are the iroh Address Types? Understanding TransportAddr and EndpointAddr

> Explore iroh address types like Relay, Ip, and Custom. Understand how TransportAddr and EndpointAddr enable flexible network connections for your iroh applications.

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

---

**The iroh address types are defined by the `TransportAddr` enum in [`iroh-base/src/endpoint_addr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/endpoint_addr.rs), which provides three variants—`Relay`, `Ip`, and `Custom`—enabling endpoints to be reached via relay servers, direct IP connections, or extensible custom transports.**

Network addressing in the iroh stack centers on flexible, multi-transport endpoint identification. The `n0-computer/iroh` repository defines these iroh address types through a non-exhaustive enum system that supports everything from traditional IP sockets to custom transport protocols. Understanding these types is essential for building applications that can connect through firewalls, NATs, and specialized network layers.

## The TransportAddr Enum: Core iroh Address Types

The fundamental `TransportAddr` enum, defined at lines 49-62 of [`iroh-base/src/endpoint_addr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/endpoint_addr.rs), represents every network-level addressing scheme supported by the protocol. This non-exhaustive enum abstracts the underlying transport mechanisms, allowing iroh endpoints to advertise multiple concurrent paths to reach a single node.

### Relay Addresses (RelayUrl)

The `Relay(RelayUrl)` variant enables connectivity through relay servers, which facilitate hole-punching and NAT traversal when direct connections are impossible. The `RelayUrl` type, implemented in [`iroh-base/src/relay_url.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/relay_url.rs) (lines 7-21), wraps an HTTPS URL pointing to a specific relay infrastructure. This variant is critical for establishing initial connectivity between peers behind restrictive firewalls.

### Direct IP Addresses (SocketAddr)

The `Ip(SocketAddr)` variant provides standard direct addressing using IPv4 or IPv6 socket addresses with port numbers. This represents the most straightforward transport path when both endpoints have public reachability or have already established NAT mappings. Direct IP addresses offer the lowest latency path when network conditions permit.

### Custom Transport Addresses (CustomAddr)

The `Custom(CustomAddr)` variant supports extensible transport protocols through opaque addressing data. Each custom address consists of a transport ID (`u64`) and arbitrary binary data, enabling integration with specialized networks like Tor or Bluetooth Low Energy. The transport ID registry is documented in [`TRANSPORTS.md`](https://github.com/n0-computer/iroh/blob/main/TRANSPORTS.md) at the repository root, where protocols like Tor (`0x544F52`) are reserved for specific implementations.

## EndpointAddr: Grouping iroh Address Types

While `TransportAddr` represents individual transport paths, `EndpointAddr` (defined in the same file) aggregates these into a complete addressing bundle. An `EndpointAddr` pairs an `EndpointId` with a collection of `TransportAddr` variants, allowing a single endpoint to advertise multiple concurrent paths—simultaneously offering relay, direct IP, and custom transport options.

## Practical Implementation of iroh Address Types

Working with these address types in Rust involves pattern matching against the `TransportAddr` variants. The following example demonstrates creating all three address types and bundling them into an `EndpointAddr`:

```rust
use iroh_base::{EndpointAddr, TransportAddr, RelayUrl, CustomAddr};
use std::net::SocketAddr;

// 1️⃣ A relay address
let relay = RelayUrl::from(
    "https://relay.example.com".parse().unwrap()
);
let relay_addr = TransportAddr::Relay(relay);

// 2️⃣ An IP address
let ip: SocketAddr = "192.0.2.10:4000".parse().unwrap();
let ip_addr = TransportAddr::Ip(ip);

// 3️⃣ A custom transport address (e.g., Tor)
let tor_pubkey = [0u8; 32];               // placeholder 32‑byte public key
let custom = CustomAddr::from_parts(0x544F52, &tor_pubkey);
let custom_addr = TransportAddr::Custom(custom);

// Build an EndpointAddr that contains all three
let endpoint = EndpointAddr::from_parts(
    /*endpoint_id=*/ Default::default(),
    vec![relay_addr, ip_addr, custom_addr],
);

// Iterate over the stored addresses
for addr in &endpoint.addrs {
    match addr {
        TransportAddr::Relay(url) => println!("Relay: {}", url),
        TransportAddr::Ip(sa)   => println!("IP: {}", sa),
        TransportAddr::Custom(c) => println!("Custom id {} data {:?}", c.id(), c.data()),
    }
}

```

The code illustrates how `TransportAddr` serves as a discriminated union, while `EndpointAddr` provides the container semantics necessary for multi-homed endpoint discovery.

## Summary

- The `TransportAddr` enum in [`iroh-base/src/endpoint_addr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/endpoint_addr.rs) defines the three core iroh address types: `Relay`, `Ip`, and `Custom`.
- **Relay addresses** use `RelayUrl` to route through relay servers for NAT traversal, defined in [`iroh-base/src/relay_url.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/relay_url.rs).
- **IP addresses** use standard `SocketAddr` for direct connectivity when network conditions permit.
- **Custom addresses** use `CustomAddr` with registered transport IDs (documented in [`TRANSPORTS.md`](https://github.com/n0-computer/iroh/blob/main/TRANSPORTS.md)) to support protocol extensions like Tor or BLE.
- `EndpointAddr` groups multiple `TransportAddr` instances with an `EndpointId`, enabling multi-path endpoint discovery.

## Frequently Asked Questions

### What is the difference between TransportAddr and EndpointAddr in iroh?

`TransportAddr` represents a single network path—such as a specific relay URL or IP address—while `EndpointAddr` aggregates multiple transport addresses under a single `EndpointId`. According to the `n0-computer/iroh` source code, an endpoint can advertise several `TransportAddr` variants simultaneously, allowing peers to choose the most appropriate connection method based on network conditions.

### How do custom transport addresses work in iroh?

Custom transport addresses use the `Custom(CustomAddr)` variant, which stores a 64-bit transport ID and opaque binary data. The transport ID identifies the specific protocol implementation (for example, `0x544F52` for Tor), while the data contains protocol-specific addressing information like public keys. Custom transport IDs must be registered in [`TRANSPORTS.md`](https://github.com/n0-computer/iroh/blob/main/TRANSPORTS.md) to avoid collisions with other implementations.

### Can an iroh endpoint have multiple address types simultaneously?

Yes, iroh endpoints routinely advertise multiple address types through `EndpointAddr`. An endpoint can simultaneously expose a `Relay` address for initial connectivity, an `Ip` address for direct communication after NAT traversal, and `Custom` addresses for specialized network protocols. This multi-address approach ensures robust connectivity across diverse network environments.

### Where are iroh address types defined in the source code?

The core address types are defined in [`iroh-base/src/endpoint_addr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/endpoint_addr.rs), which contains the `TransportAddr` and `EndpointAddr` structs. The `RelayUrl` type resides in [`iroh-base/src/relay_url.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/relay_url.rs), while transport ID registrations for custom addresses are documented in the repository's [`TRANSPORTS.md`](https://github.com/n0-computer/iroh/blob/main/TRANSPORTS.md) file at the root level.