# Iroh Connections Fallback to Relay Servers: Automatic Failover Explained

> Discover how Iroh connections automatically fallback to relay servers when direct P2P connections fail, ensuring reliable data transfer with path selection.

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

---

**Yes, Iroh automatically falls back to relay servers when direct peer-to-peer connections fail, using a path selector that prioritizes direct IP paths while treating relay transport as a backup option.**

The n0-computer/iroh library implements seamless connection failover through its path selection architecture. When building peer-to-peer applications with Iroh, **Iroh connections fallback to relay servers** transparently whenever NAT traversal or firewall restrictions block direct connectivity, requiring no additional application code.

## How the BiasedRttPathSelector Prioritizes Direct Paths

The default path selection logic lives in [`iroh/src/socket/remote_map/biased_rtt_path_selector.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket/remote_map/biased_rtt_path_selector.rs). The `BiasedRttPathSelector` sorts candidate paths by biased round-trip time, preferring IPv6 over IPv4, and **treating relay paths as the lowest-priority option**.

This architecture ensures that relays function strictly as a backup mechanism. The selector only returns a relay address after all direct candidates have been rejected or deemed unreachable, making the fallback behavior automatic and transparent to the application layer.

## Configuring Relay Servers as Fallback Transport

Relay servers are configured through the `Builder::relay_mode` method in `iroh/src/endpoint.rs#L442-L452`. When you configure relay mode, the relay transport is added to the endpoint's available transports but explicitly marked as a *fallback* transport.

This means the relay infrastructure is registered and maintained, but the `Endpoint` will not utilize it unless the path selector determines that direct IP paths are unavailable. The `RelayActor` (found in [`iroh/src/socket/transports/relay/actor.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket/transports/relay/actor.rs)) maintains persistent QUIC connections to these configured relay servers, supplying a ready-to-use `Client` when the selector ultimately chooses a relay path.

## The Connection Flow: From Direct to Relay

The failover process follows a strict sequence implemented across several core components:

1. **Address Resolution**: When `Endpoint::connect` is called (see `iroh/src/endpoint.rs#L1024-L1030`), the endpoint resolves the remote `EndpointAddr` into a list of candidate addresses. This list includes direct IP addresses first, followed by any available relay URLs.

2. **Path Selection**: The `BiasedRttPathSelector` orders the candidates, always ranking direct paths above relay paths based on the biased RTT algorithm.

3. **Fallback Execution**: If none of the direct candidates are reachable (due to NAT traversal failure, firewall restrictions, or absent public IP), the selector picks the relay transport. The `RelayActor` supplies an active QUIC client to the selected relay, and the connection completes over that relay connection.

4. **Address Updates**: The endpoint continually updates its own `EndpointAddr` via the `Watcher` mechanism (see `iroh/src/endpoint.rs#L1482-L1490`), advertising reachable direct addresses and the current relay URL. This ensures peers dialing the endpoint know whether direct connectivity is possible or if they must initiate a relay fallback immediately.

## Practical Implementation Example

The following code demonstrates the default configuration that enables automatic relay fallback:

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

#[tokio::main]
async fn main() -> Result<(), iroh::Error> {
    // Build an endpoint with the default relay configuration (RelayMode::Default)
    let ep = Endpoint::builder(presets::N0)
        .relay_mode(iroh::relay::RelayMode::Default) // relay is a fallback
        .bind()
        .await?;

    // Remote address may contain direct IPs, but also a relay URL.
    // If the direct IPs are unreachable, the connection will automatically use the relay.
    let remote_addr = "iroh://4a5b6c...@example.com"; // example EndpointAddr
    let conn = ep.connect(remote_addr, b"my-alpn").await?;

    println!("connection established (direct or via relay)");
    Ok(())
}

```

In this example, `relay_mode(RelayMode::Default)` registers the default relay server(s) as a fallback transport. The `connect` call does not need to specify a relay URL; the endpoint uses the relay map only when direct IP routes fail, as determined by the `BiasedRttPathSelector`.

## Summary

- **Iroh connections fallback to relay servers** automatically when direct peer-to-peer connectivity cannot be established.
- The `BiasedRttPathSelector` in [`iroh/src/socket/remote_map/biased_rtt_path_selector.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket/remote_map/biased_rtt_path_selector.rs) treats relay paths as the lowest-priority option, ensuring direct paths are always attempted first.
- The `Builder::relay_mode` method registers relay servers as fallback transports without requiring manual intervention during connection.
- The `RelayActor` manages persistent QUIC connections to relay servers, providing seamless failover when the path selector rejects all direct candidates.
- No application code changes are required to handle the fallback; the behavior is transparent and controlled by the endpoint's path selection policy.

## Frequently Asked Questions

### How does Iroh decide when to use a relay server instead of a direct connection?

The `BiasedRttPathSelector` evaluates all candidate paths for a connection, ranking them by biased round-trip time with a preference for IPv6 over IPv4. Relay paths are explicitly ranked as the lowest priority. Only when all direct IP candidates are deemed unreachable does the selector choose a relay path, triggering the connection to route through the relay server.

### Do I need to configure relay fallback manually in my Iroh application?

No. When you configure `relay_mode` using `RelayMode::Default` or custom relay maps, the relay transport is automatically registered as a fallback. As shown in `iroh/src/endpoint.rs#L442-L452`, the relay is added to the transport list with fallback semantics, meaning the `Endpoint` will only utilize it when the path selector determines direct connectivity is impossible.

### What happens if both direct connections and the relay server fail?

If the `BiasedRttPathSelector` cannot establish connectivity through any direct IP addresses and the relay connection also fails, the `Endpoint::connect` call will return an error. The connection attempt fails only after exhausting all available paths, including the configured relay servers. The application receives the connection failure and can implement retry logic if desired.

### Is traffic encrypted when using Iroh relay fallback?

Yes. According to the implementation in [`iroh/src/socket/transports/relay/actor.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket/transports/relay/actor.rs), the `RelayActor` maintains persistent QUIC connections to relay servers. All traffic forwarded through the relay uses these QUIC connections, which provide encryption and authentication. The relay server forwards encrypted datagrams between peers without accessing the plaintext content, ensuring end-to-end security even during fallback scenarios.