# How to Connect to an Iroh Endpoint Using Only Its EndpointId

> Connect to an Iroh endpoint using only its EndpointId by enabling the N0 preset. Automatically resolve addresses and establish QUIC connections without manual IP or relay setup.

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

---

**You can connect to an Iroh node using just its `EndpointId` by enabling the `N0` preset, which automatically resolves the node's network address via DNS-based discovery and establishes a QUIC connection without requiring manual IP or relay configuration.**

The `n0-computer/iroh` crate supports **address-free connections** through built-in DNS resolution that maps an endpoint's public key to its network location. When you want to connect to an Iroh endpoint using only its EndpointId, the library handles all transport address discovery, hole-punching, and relay fallback internally.

## What Is an EndpointId?

In Iroh, every endpoint is cryptographically identified by its **EndpointId**, which is the public key corresponding to the endpoint's `SecretKey`. This identifier is stable across network changes and serves as the sole addressing requirement when using the discovery service.

Rather than requiring you to track IP addresses or relay URLs manually, Iroh treats the EndpointId as a self-authenticating address. The library resolves this identifier to concrete network paths through a **PKARR DNS backend** that queries DNS records containing the endpoint's current `TransportAddr` list.

## How DNS-Based Address Discovery Works

When you use the default `N0` preset, Iroh installs a DNS resolver that transforms an EndpointId into a resolvable DNS name. The resolver encodes the ID using the `BASE32_DNSSEC` alphabet and constructs a query name in the format:

```

<base32-encoded-id>.iroh.invalid

```

The DNS lookup (performed via standard DNS or DoH) returns `PTR` and `TXT` records containing the remote endpoint's `TransportAddr`s—either direct UDP addresses or relay URLs. Simultaneously, the library encodes the EndpointId for TLS server name indication using `iroh::tls::name::encode`, ensuring that the TLS session ticket cache is correctly partitioned for 0-RTT support.

This resolution happens lazily during the connection attempt, allowing the endpoint to attempt direct UDP hole-punching before falling back to relay connections.

## Connecting with the N0 Preset

To connect to an Iroh endpoint using only its EndpointId, construct your local endpoint with the `N0` preset and call `Endpoint::connect` with the target identifier and your protocol's ALPN.

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

#[tokio::main]
async fn main() -> Result<()> {
    // Build a local endpoint with the N0 preset – this enables DNS lookup.
    let endpoint = Endpoint::bind(presets::N0).await?;

    // Remote endpoint identifier obtained from the remote side.
    let remote_id: EndpointId = "7dl2ff6emqi2qol3l382krodedij45bn3nh479hqo14a32qpr8kg"
        .parse()
        .expect("valid endpoint id");

    // ALPN identifying the protocol.
    const MY_ALPN: &[u8] = b"myapp/example/0";

    // Connect – the library resolves the address from the ID internally.
    let conn = endpoint.connect(remote_id, MY_ALPN).await?;

    // Use the connection (e.g., open a bidirectional stream).
    let (mut send, mut recv) = conn.open_bi().await?;
    send.write_all(b"Hello from the client!").await?;
    send.finish()?;
    let reply = recv.read_to_end(1024).await?;
    println!("Remote replied: {}", String::from_utf8_lossy(&reply));

    // Clean shutdown.
    endpoint.close().await;
    Ok(())
}

```

The `N0` preset automatically adds the DNS resolver to the endpoint's address-resolution pipeline in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs). When `connect` is invoked, the endpoint internally encodes the ID to a DNS name, queries for transport addresses, attempts direct connection, and establishes a QUIC connection authenticated by the remote's public key.

## Manual Address Resolution

If you need to inspect the concrete addresses before establishing a connection, you can query the DNS resolver directly using the `iroh-dns` crate.

```rust
use iroh_dns::{Client, Resolver};
use iroh_base::EndpointId;

#[tokio::main]
async fn main() {
    let resolver = Resolver::default(); // uses system DNS/DoH configuration
    let remote_id = EndpointId::from_z32(
        "7dl2ff6emqi2qol3l382krodedij45bn3nh479hqo14a32qpr8kg"
    )
    .unwrap();

    // Resolve to a list of TransportAddrs (IP + relay URLs)
    let addrs = resolver.resolve(remote_id).await.unwrap();

    println!("Resolved addresses:");
    for a in addrs {
        println!("  {}", a);
    }
}

```

This approach is useful for debugging or when you need to implement custom connection logic while still leveraging Iroh's discovery infrastructure.

## Key Implementation Details

The address discovery and connection flow is implemented across several source files:

- **[`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs)**: Implements `Endpoint::bind`, `Endpoint::connect`, and the address-resolution pipeline that integrates the `N0` preset's DNS resolver.
- **[`iroh/src/tls/name.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls/name.rs)**: Contains the logic for encoding an `EndpointId` to a DNS name (`<base32>.iroh.invalid`) and decoding it for TLS server-name verification.
- **[`iroh-dns/src/endpoint_info.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/endpoint_info.rs)**: Defines the DNS record format that carries the list of `TransportAddr`s for an endpoint.
- **[`iroh-dns/src/dns.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/dns.rs)**: Implements the DNS and DoH resolver used by the `N0` preset to perform PKARR lookups.
- **[`iroh/examples/connect.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/connect.rs)**: Demonstrates low-level connection establishment when you already know direct addresses and relay URLs.
- **[`iroh/examples/listen.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/listen.rs)**: Shows the listening side configuration, useful for testing connections.

## Summary

- **EndpointId** is the public key of an Iroh node and serves as the stable identifier for connections.
- The **`N0` preset** enables automatic DNS-based address discovery, eliminating the need to manage IP addresses or relay URLs manually.
- Iroh constructs DNS names using **Base32 DNSSEC encoding** of the EndpointId to query for transport addresses.
- Call **`Endpoint::connect`** with only the EndpointId and ALPN; the library handles resolution, hole-punching, and relay fallback.
- For debugging, query the **`Resolver`** directly from `iroh-dns` to inspect resolved `TransportAddr`s before connecting.

## Frequently Asked Questions

### What happens if the DNS lookup fails when connecting by EndpointId?

If the DNS resolver cannot find records for the given EndpointId, the `connect` call will fail with a resolution error. Ensure the remote endpoint is running with the `N0` preset (or equivalent DNS publishing enabled) and that your local endpoint has internet access to query the DNS infrastructure.

### Do I need to configure any DNS servers manually to use the N0 preset?

No. The `N0` preset automatically configures the DNS resolver to use appropriate DNS-over-HTTPS endpoints and infrastructure maintained by the Iroh network. You do not need to modify system DNS settings or manage resolver configuration manually.

### Can I connect to an endpoint that is behind a NAT or firewall?

Yes. When connecting to an Iroh endpoint using only its EndpointId, the library automatically attempts **UDP hole-punching** using the direct addresses returned by DNS. If direct connectivity fails, it transparently falls back to using the **relay URLs** included in the DNS records, ensuring connectivity even when both endpoints are behind NAT.

### Is the EndpointId connection method secure?

Yes. The EndpointId is the cryptographic public key of the remote endpoint. During the QUIC handshake, Iroh verifies that the remote peer possesses the corresponding private key, preventing man-in-the-middle attacks. Additionally, the TLS server name is uniquely derived from the EndpointId via `iroh::tls::name::encode`, ensuring certificate validation is bound to the specific endpoint identity.