# Iroh Address Lookup Services for Endpoint Discovery: Pkarr, DNS, and Mainline-DHT

> Discover remote endpoints with Iroh's address lookup services, supporting Pkarr, DNS TXT records, and Mainline-DHT. Find peers efficiently with Iroh.

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

---

**Iroh discovers remote endpoints through a pluggable address lookup system that supports Pkarr relays, DNS TXT records, in-memory storage for testing, and optional Mainline-DHT resolution.**

The n0-computer/iroh repository provides a robust framework for peer discovery through the `AddressLookup` trait. These iroh address lookup services allow applications to publish their endpoint information and resolve remote peers using multiple discovery mechanisms that can be combined for redundancy.

## How Iroh Endpoint Discovery Works

Iroh’s endpoint discovery relies on the **`AddressLookup`** trait, which abstracts how `EndpointInfo`—containing relay URLs, IP addresses, and other connection details—is published and retrieved. The `Builder` struct in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) exposes an `address_lookup` method that accepts any implementation of this trait, allowing developers to chain multiple lookup services together.

## Supported Address Lookup Services

Iroh ships with four concrete address lookup implementations in the core crate, plus an optional external crate for decentralized DHT resolution.

### Pkarr Publisher and Resolver

The **`PkarrPublisher`** and **`PkarrResolver`** structs—defined in [`iroh/src/address_lookup/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/pkarr.rs)—provide bidirectional endpoint discovery through Pkarr relays.

- **Publishing**: `PkarrPublisher` sends an HTTP PUT request to a configured pkarr relay, storing a signed packet containing the endpoint’s `EndpointInfo`. The relay stores this in the Mainline-DHT or a local cache.
- **Resolution**: `PkarrResolver` queries the same relay via HTTP GET to retrieve the signed packet and parse it into an `AddressLookupItem`.

These services support both production and staging relays through builder APIs that configure the TLS context and relay endpoints.

### DNS Address Lookup

The **`DnsAddressLookup`** service in [`iroh/src/address_lookup/dns.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/dns.rs) resolves endpoints by querying DNS TXT records. It looks up records following the format:

```

_iroh.<z32-encoded-EndpointId>.<origin-domain>

```

For example: `_iroh.abc123.n0.com`. The TXT records contain key-value pairs such as `relay=<url>` that describe how to reach the endpoint. This service supports both staging and production origin domains.

### In-Memory Lookup

The **`MemoryLookup`** struct in [`iroh/src/address_lookup/memory.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/memory.rs) stores `EndpointInfo` objects in a local `HashMap`. This implementation is designed for unit tests and temporary setups where no external network service is required, allowing for fast, isolated endpoint discovery during development.

### Mainline-DHT Lookup

For decentralized discovery without relying on Pkarr relays, iroh supports **Mainline-DHT resolution** through the auxiliary crate `iroh-mainline-address-lookup`. This crate exposes the same `PkarrResolver` and `PkarrPublisher` APIs but forwards queries directly to the BitTorrent Mainline DHT rather than through an HTTP relay.

## Configuring Address Lookup in Iroh

You can configure iroh to use multiple lookup services simultaneously through the endpoint builder pattern.

### Combined Publishing and Resolution

To publish via Pkarr while resolving via both Pkarr and DNS:

```rust
use iroh::endpoint::Builder;
use iroh::address_lookup::{PkarrPublisher, DnsAddressLookup};

let builder = Builder::default()
    // Publish endpoint info to the public pkarr relay
    .address_lookup(PkarrPublisher::n0_dns())
    // Resolve peers via DNS TXT records under iroh.link
    .address_lookup(DnsAddressLookup::n0_dns());

let endpoint = builder.build().await?;

```

### Resolver-Only Configuration

For clients that only need to resolve remote endpoints without publishing their own:

```rust
use iroh::address_lookup::PkarrResolver;

let resolver = PkarrResolver::n0_dns().build(tls_config);
let lookup_item = resolver.resolve(endpoint_id).await?;

```

### Using the N0 Preset

The **`N0`** preset in [`iroh/src/endpoint/presets.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/presets.rs) wires both Pkarr and DNS services together automatically:

```rust
use iroh::endpoint::presets::N0;

let endpoint = N0::new(secret_key).await?;

```

## Key Source Files and Implementation Details

| File | Purpose |
|------|---------|
| [`iroh/src/address_lookup/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/pkarr.rs) | Implements `PkarrPublisher` and `PkarrResolver` with HTTP PUT/GET logic and relay constants |
| [`iroh/src/address_lookup/dns.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/dns.rs) | Contains `DnsAddressLookup` with TXT record parsing for `_iroh.*` subdomains |
| [`iroh/src/address_lookup/memory.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/memory.rs) | Provides `MemoryLookup` for test environments using in-memory storage |
| [`iroh/src/endpoint/presets.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/presets.rs) | Defines the `N0` preset that combines Pkarr and DNS lookups |
| [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) | Exposes `Builder::address_lookup()` for registering any `AddressLookup` implementation |

## Summary

- **Pkarr services** (`PkarrPublisher`/`PkarrResolver`) use HTTP requests to relays that store data in the Mainline-DHT.
- **DNS lookup** (`DnsAddressLookup`) queries TXT records at `_iroh.<z32-id>.<domain>` to find relay URLs.
- **In-memory lookup** (`MemoryLookup`) provides local hashing for unit tests.
- **Mainline-DHT** resolution is available via the external `iroh-mainline-address-lookup` crate for decentralized operation.
- The **`AddressLookup`** trait allows composable configuration through `Builder::address_lookup()`.

## Frequently Asked Questions

### What is the difference between PkarrPublisher and PkarrResolver?

`PkarrPublisher` publishes your local endpoint's information to a Pkarr relay using HTTP PUT, making it discoverable by other peers. `PkarrResolver` queries that same relay via HTTP GET to retrieve endpoint information for a specific `EndpointId`. Both are implemented in [`iroh/src/address_lookup/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/pkarr.rs) and share the same underlying packet format but serve opposite directions of data flow.

### How does iroh DNS address lookup format endpoint information?

Iroh uses DNS TXT records with the subdomain pattern `_iroh.<z32-encoded-endpoint-id>.<origin-domain>`, such as `_iroh.abc123.n0.com`. These records contain key-value pairs like `relay=https://relay.example.com` that the `DnsAddressLookup` service parses to construct connection paths to remote endpoints.

### Can I use multiple address lookup services simultaneously?

Yes. The `Builder::address_lookup()` method in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) can be called multiple times to chain services. For example, you can register both `PkarrPublisher` for publishing and `DnsAddressLookup` for resolution, or multiple resolvers for redundant peer discovery across different namespaces.

### What is the N0 preset in iroh endpoint configuration?

The `N0` preset, defined in [`iroh/src/endpoint/presets.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/presets.rs), is a convenience configuration that automatically wires both `PkarrPublisher` and `DnsAddressLookup` using n0's production infrastructure. It provides a one-line setup (`N0::new(secret_key).await?`) for applications that want standard, production-ready endpoint discovery without manually configuring individual lookup services.