# How Does Iroh Connection Migration Work After Direct Connection Is Established?

> Discover how Iroh connection migration maintains streams during network path changes. Learn about QUIC transport and seamless peer-to-peer communication.

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

---

**Iroh enables connection migration by configuring its underlying QUIC transport with `server_handshake_migration(true)`, allowing peers to switch network paths—including fallback to relays or IP address changes—without resetting cryptographic state or interrupting active streams.**

Iroh is a peer-to-peer networking library developed by n0-computer that builds its transport layer on top of the **noq** QUIC implementation. Once a direct peer-to-peer connection is established, the library leverages QUIC's native path migration capabilities to ensure that network changes do not force connection teardown. This architectural choice allows the underlying QUIC stack to automatically handle address validation and path switching while preserving all application-level streams.

## Where Migration Gets Enabled in the Source Code

Iroh activates handshake migration in two critical locations within its core networking stack. These configuration points ensure that every endpoint created through the library inherits migration support by default.

### Transport Configuration in [`iroh/src/endpoint/quic.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/quic.rs)

The default QUIC transport configuration is initialized in the `QuicTransportConfigBuilder::new` method, where migration is explicitly enabled for all endpoints:

```rust
// Located in iroh/src/endpoint/quic.rs around line 1559-1562
cfg.server_handshake_migration(true);

```

This setting ensures that any `Endpoint` constructed via `QuicTransportConfig::builder()` automatically permits the server side of a connection to accept path migration requests after the initial handshake completes.

### Connection Setup in [`iroh/src/socket.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket.rs)

When an endpoint initiates a direct connection through the high-level `connect` API, the `socket_connect` function applies the same migration flag to the connection-specific transport configuration:

```rust
// Located in iroh/src/socket.rs around line 2619-2621
transport_config.server_handshake_migration(true);

```

By setting this flag during the connection setup phase, Iroh guarantees that individual connections—regardless of how the endpoint was initially configured—can survive network path changes.

## How Path Migration Works in QUIC

When **handshake migration** is enabled, the QUIC protocol allows a client to discover and switch to a new network path after the initial cryptographic handshake has finished. The mechanism relies on standardized frame types and automatic address probing handled entirely within the transport layer.

### PATH_CHALLENGE and PATH_RESPONSE Frames

When a peer detects a network change—such as a NAT rebinding, Wi-Fi to cellular transition, or VPN activation—it sends a **PATH_CHALLENGE** frame over the new path. The remote peer responds with a **PATH_RESPONSE** frame to validate reachability. Because `server_handshake_migration` is enabled, the server accepts this new path as valid for the existing connection, preserving the connection ID and cryptographic keys.

### Network Resilience Without Application Intervention

Because the migration logic executes inside the underlying QUIC library, Iroh applications do not need to detect network changes or re-establish connections manually. The transport automatically performs the following actions:

- **Probes new paths** using nonce-based challenges to prevent address spoofing
- **Validates path viability** before switching primary packet transmission
- **Maintains stream state** so that all bidirectional streams continue uninterrupted

## Practical Migration Scenarios

Iroh leverages connection migration to handle two common real-world networking challenges without dropping active sessions.

### Direct-to-Relay Fallback

If a direct connection was initially established but later fails due to firewall changes or symmetric NAT placement, the client can migrate to a relay-mediated path. The existing QUIC connection transitions to the new path via standard migration frames, allowing the application to continue using the same connection object without reconnecting or re-authenticating.

### IP Address Changes

When a device changes its local IP address—such as switching from Ethernet to Wi-Fi or toggling a VPN—the QUIC connection migrates to the new address automatically. The remote peer validates the new path through the challenge-response mechanism, and the connection continues as if no change occurred.

## Implementing Connection Migration in Your Application

To take advantage of Iroh's connection migration capabilities, create an endpoint using the default transport configuration and initiate connections normally. The migration support is already baked into the transport settings.

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

/// Creates an endpoint with migration support enabled by default.
async fn create_migrating_endpoint() -> anyhow::Result<Endpoint> {
    // The default builder automatically enables server_handshake_migration
    let transport_cfg = QuicTransportConfig::builder().build();

    let endpoint = Endpoint::builder()
        .transport_cfg(transport_cfg)
        .bind()
        .await?;
    
    Ok(endpoint)
}

/// Connects to a peer with automatic migration support.
async fn connect_with_migration(
    endpoint: &Endpoint,
    peer_id: iroh::endpoint::EndpointId,
) -> anyhow::Result<()> {
    // The underlying transport allows future migration after this handshake
    let connection = endpoint.connect(peer_id).await?;
    
    // If the network changes later, the QUIC library automatically
    // attempts migration without requiring intervention here
    Ok(())
}

```

As shown in the example above, no additional flags are required at the application layer. The configuration set in [`iroh/src/endpoint/quic.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/quic.rs) and [`iroh/src/socket.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket.rs) ensures that every connection created through these APIs inherits migration capabilities.

## Summary

- **Iroh enables QUIC handshake migration** by setting `server_handshake_migration(true)` in both the default transport builder and the socket connection setup.
- **Migration is handled automatically** by the underlying noq QUIC implementation using PATH_CHALLENGE/PATH_RESPONSE frames.
- **Connections survive network changes** such as IP address updates or fallback to relay servers without tearing down streams.
- **No application code is required** to manage the migration process; the transport layer handles path validation and switching transparently.

## Frequently Asked Questions

### What triggers a connection migration in Iroh?

A migration is triggered when the underlying QUIC stack detects a potential new network path, such as when the local IP address changes or when a direct path becomes unreachable and a relay becomes available. The client sends a PATH_CHALLENGE frame to probe the new path, and if the server responds correctly, the connection switches to the new route.

### Does migration preserve open streams and application state?

Yes. Because migration occurs at the transport layer after the cryptographic handshake, all stream IDs, flow control credits, and application state remain intact. The connection maintains its cryptographic context, so higher-level protocols continue uninterrupted.

### How does Iroh handle migration when switching from direct to relayed paths?

If a direct connection degrades, Iroh can migrate the existing QUIC connection to a relay-mediated path. The connection object remains valid; only the underlying transport path changes. This allows seamless fallback to relay infrastructure without requiring the application to reconnect or re-negotiate session parameters.

### Is additional application code required to handle network changes?

No. The migration logic is encapsulated within the QUIC transport configuration set at endpoint creation. As long as you use the standard `QuicTransportConfig::builder()` or the high-level `Endpoint::connect` API, the `server_handshake_migration` flag is already enabled, and the library handles all path switching automatically.