# How to Configure iroh Relay Servers Using RelayMode

> Configure iroh relay servers with RelayMode by selecting Default, Staging, Custom, or Disabled. Control NAT traversal when direct QUIC paths fail. Learn how in this guide.

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

---

**Use `Builder::relay_mode()` to select `RelayMode::Default`, `Staging`, `Custom`, or `Disabled` on your iroh `Endpoint` to control which relay servers facilitate NAT traversal when direct QUIC paths are unavailable.**

When building peer-to-peer applications with the n0-computer/iroh crate, endpoints rely on relay servers to establish connectivity across restrictive firewalls and NAT. The `RelayMode` enum, defined in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs), provides the primary mechanism to configure iroh relay servers, determining whether your node uses production infrastructure, staging environments, custom relay maps, or operates without relay assistance entirely.

## Understanding RelayMode Architecture

The `RelayMode` enum controls how your endpoint discovers and connects to relay infrastructure. When an `Endpoint` starts, it measures latency to available relays and selects the fastest as its *home relay*.

### The RelayMode Enum Variants

As implemented in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) around line 1910, the enum offers four distinct variants:

- **Disabled**: Removes relay transport entirely. Connections must be direct or use alternative address lookup services.
- **Default**: Uses the production relay map shipped with iroh (`crate::defaults::prod::default_relay_map()`).
- **Staging**: Uses the staging relay map (`crate::defaults::staging::default_relay_map()`).
- **Custom(RelayMap)**: Accepts an explicit `RelayMap` built from `RelayUrl` instances.

### Transport Integration

`RelayMode` implements `From<RelayMode> for Option<TransportConfig>` in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) (lines 153-170). This conversion translates your mode selection into the underlying QUIC transport configuration. When you call `Builder::relay_mode()`, the builder stores the resulting `TransportConfig::Relay` in its transport list. Selecting `RelayMode::Disabled` removes the relay transport entirely, while other variants populate it with the appropriate relay URLs.

## Configuring Relay Modes in Practice

The `Endpoint` builder consumes `RelayMode` via the `relay_mode()` method. After binding, the endpoint contacts the selected relays when `Endpoint::online()` is awaited.

### Using Production Relays (Default)

The default configuration uses iroh's production relay fleet. This is the implicit choice if you don't specify a mode, but you can set it explicitly:

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

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let ep = Endpoint::builder(presets::N0)
        .relay_mode(RelayMode::Default)
        .bind()
        .await?;
    
    ep.online().await;
    println!("Connected via home relay: {:?}", ep.addr().relay_urls().next());
    Ok(())
}

```

According to the source code in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) (lines 1919-1922), `RelayMode::Default` resolves to the production relay map.

### Switching to Staging Relays

For testing or CI environments, use the staging relay infrastructure:

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

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let ep = Endpoint::builder(presets::N0)
        .relay_mode(RelayMode::Staging)
        .bind()
        .await?;
    
    ep.online().await;
    println!("Using staging relay(s)");
    Ok(())
}

```

This variant maps to `crate::defaults::staging::default_relay_map()` as shown in lines 1920-1923 of [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs).

### Providing Custom Relay URLs

For private deployments, construct a custom relay map using the `RelayMode::custom()` helper (defined around lines 50-57):

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

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let custom = RelayMode::custom([
        "https://use1-1.relay.n0.iroh.link.".parse::<RelayUrl>()?,
        "https://euw-1.relay.n0.iroh.link.".parse::<RelayUrl>()?,
    ]);
    
    let ep = Endpoint::builder(presets::N0)
        .relay_mode(custom)
        .bind()
        .await?;
    
    ep.online().await;
    println!("Custom relay map active");
    Ok(())
}

```

Note that relay URLs should include a trailing dot for DNS stability when parsing.

### Disabling Relays Entirely

To force direct connections only, disable the relay transport:

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

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let ep = Endpoint::builder(presets::N0)
        .relay_mode(RelayMode::Disabled)
        .bind()
        .await?;
    
    // online() returns immediately since no relay is contacted
    println!("Relay disabled; direct connections only");
    Ok(())
}

```

As implemented in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) (lines 1912-1915), this variant prevents the relay transport from being added to the endpoint's transport configuration.

## Environment-Based Configuration

You can override the default relay mode without code changes using the `IROH_FORCE_STAGING_RELAYS` environment variable. When set to a non-empty value, the `default_relay_mode()` function (lines 64-73 in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs)) automatically returns `RelayMode::Staging`.

```rust
use iroh::{Endpoint, RelayMode};

fn main() {
    std::env::set_var("IROH_FORCE_STAGING_RELAYS", "1");
    
    // This now returns RelayMode::Staging regardless of build configuration
    let mode = iroh::default_relay_mode();
    assert!(matches!(mode, RelayMode::Staging));
}

```

This is particularly useful for CI pipelines or test-only deployments where you want to ensure staging infrastructure usage across deployed binaries without modifying source code.

## Summary

- **`RelayMode`** controls how iroh endpoints discover and connect to relay servers for NAT traversal.
- **Four variants** are available: `Default` (production), `Staging` (test infrastructure), `Custom` (user-defined `RelayMap`), and `Disabled` (no relay).
- **Implementation** occurs in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) where `RelayMode` converts to `TransportConfig` and integrates with the QUIC stack via `Builder::relay_mode()` (lines 554-577).
- **Configuration** requires calling `relay_mode()` on the endpoint builder before `bind()`.
- **Environment override** `IROH_FORCE_STAGING_RELAYS` forces staging mode without code changes, returning `RelayMode::Staging` from `default_relay_mode()`.

## Frequently Asked Questions

### What is the difference between RelayMode::Default and RelayMode::Staging?

`RelayMode::Default` uses the production relay fleet (`default_relay_map()` from the prod defaults), while `RelayMode::Staging` connects to the staging infrastructure used for testing. The staging environment is useful for CI pipelines and development when you want to avoid hitting production relays with test traffic.

### How do I run iroh without any relay servers?

Set `RelayMode::Disabled` when building your endpoint. This removes the relay transport entirely from the QUIC configuration in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) (lines 153-170), forcing the endpoint to rely solely on direct connections or other address discovery mechanisms.

### Can I use multiple custom relay URLs in iroh?

Yes. The `RelayMode::custom()` helper accepts any iterable of `RelayUrl` values, allowing you to specify multiple relay servers. The endpoint will measure latency to all provided relays and select the fastest one as its home relay. Ensure URLs include a trailing dot for DNS stability when parsing strings into `RelayUrl` instances.

### How does the IROH_FORCE_STAGING_RELAYS environment variable work?

When `IROH_FORCE_STAGING_RELAYS` is set to any non-empty value, the `default_relay_mode()` function in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) (lines 64-73) returns `RelayMode::Staging` instead of `RelayMode::Default`. This allows operators to force staging infrastructure usage across deployed binaries without recompiling, making it ideal for containerized test environments.