# How to Set Up Address Lookup Services in iroh: Complete Configuration Guide

> Configure iroh address lookup services by registering PkarrPublisher or DnsAddressLookup with Endpoint::builder().address_lookup() before binding. Get started today.

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

---

**Configure address lookup services in iroh by registering implementations of the `AddressLookup` trait—such as `PkarrPublisher` or `DnsAddressLookup`—via `Endpoint::builder().address_lookup()` before binding the endpoint.**

When building peer-to-peer applications with iroh, endpoints need to discover how to reach remote peers using only an **EndpointId**. The address lookup subsystem handles this by publishing local addressing information to external services and resolving remote endpoint data through a unified registry. This guide demonstrates how to configure these services using the actual implementation from the `n0-computer/iroh` repository.

## Core Concepts

The address lookup system is built on several key abstractions defined in [`iroh/src/address_lookup.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup.rs).

### AddressLookup Trait

The **`AddressLookup`** trait defines the minimal interface for any lookup service. Located at lines 33-50, it requires two methods: `publish` to advertise local endpoint data, and `resolve` to fetch remote endpoint information. This trait enables custom implementations while maintaining a consistent API for the endpoint.

### AddressLookupBuilder

The **`AddressLookupBuilder`** trait (lines 41-50) allows services to defer final initialization until the endpoint configuration is complete. Builders are converted into `AddressLookup` instances once the endpoint is fully constructed, enabling services to access the endpoint's own configuration parameters during setup.

### AddressLookupServices Registry

Each `Endpoint` maintains an **`AddressLookupServices`** registry (lines 60-89) that manages multiple lookup services simultaneously. This registry stores boxed `AddressLookup` instances, maintains an optional address filter, and tracks the last published `EndpointData`. When resolving remote addresses, it merges result streams from all registered services, ensuring that slower successful lookups are not hidden by faster failures.

### AddrFilter

The **`AddrFilter`** type—re-exported via `iroh::address_lookup::AddrFilter` from the `iroh-dns` crate—provides a user-supplied function that can prune or reorder addresses before publication. For example, you can configure a filter to publish only relay URLs while omitting direct socket addresses.

## Built-in Service Types

The iroh ecosystem provides several production-ready implementations for common discovery scenarios.

### DNS Resolution

The **`DnsAddressLookup`** service, implemented in [`iroh-dns/src/dns.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/dns.rs), resolves EndpointIds using standard DNS queries. The convenience constructor `DnsAddressLookup::n0_dns()` configures the resolver to use the public n0.computer DNS zone.

### Pkarr Publishing

The **`PkarrPublisher`** service, found in [`iroh-dns/src/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/pkarr.rs), publishes endpoint addressing information to a pkarr relay and resolves others through HTTP. Use `PkarrPublisher::n0_dns()` to target the public n0.computer pkarr relay infrastructure.

### Memory Lookup

The **`MemoryLookup`** service provides an in-process implementation ideal for testing and embedded scenarios. Defined in [`iroh/src/memory.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/memory.rs), it maintains a local hash map of endpoint addresses without network dependencies.

## Configuration Examples

### Configure DNS and Pkarr Services

To enable both DNS resolution and pkarr publishing for a production endpoint, chain the builders before calling `bind()`:

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

#[tokio::main]
async fn main() -> Result<(), iroh::Error> {
    let ep = Endpoint::builder(presets::Minimal)
        .addr_filter(AddrFilter::relay_only())
        .address_lookup(address_lookup::PkarrPublisher::n0_dns())
        .address_lookup(address_lookup::DnsAddressLookup::n0_dns())
        .bind()
        .await?;

    Ok(())
}

```

This configuration automatically publishes the local relay URL via pkarr and can resolve remote peers using DNS.

### Use Memory Lookup for Testing

For isolated integration tests, use the memory-backed implementation:

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

let memory = MemoryLookup::new();
let ep = Endpoint::builder(presets::Minimal)
    .address_lookup(memory)
    .bind()
    .await?;

```

This avoids external network calls while maintaining full API compatibility.

### Filter Published Addresses

Apply filtering after endpoint construction to restrict which addresses are shared:

```rust
let ep = Endpoint::builder(presets::Minimal).bind().await?;
let lookup = ep.address_lookup().expect("endpoint still open");

// Only publish relay URLs, discard direct IPs
lookup.set_addr_filter(address_lookup::AddrFilter::relay_only());

```

The filter applies to all subsequent publish operations.

### Implement Custom Resolvers

For specialized discovery protocols, implement the `AddressLookup` trait directly:

```rust
struct MyResolver;

impl iroh::address_lookup::AddressLookup for MyResolver {
    fn resolve(
        &self,
        endpoint_id: iroh_base::EndpointId,
    ) -> Option<BoxStream<
        Result<iroh::address_lookup::Item, iroh::address_lookup::Error>
    >> {
        // Custom resolution logic here
        None
    }
}

let ep = Endpoint::builder(presets::Minimal).bind().await?;
ep.address_lookup().unwrap().add(MyResolver);

```

## Key Source Files

Understanding the implementation requires examining these specific files in the `n0-computer/iroh` repository:

- **[`iroh/src/address_lookup.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup.rs)** – Core traits (`AddressLookup`, `AddressLookupBuilder`), the `AddressLookupServices` registry, and the merge stream implementation.
- **[`iroh-dns/src/dns.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/dns.rs)** – DNS resolver implementation and `DnsAddressLookup` types.
- **[`iroh-dns/src/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/pkarr.rs)** – Pkarr publisher (`PkarrPublisher`) and resolver implementations.
- **[`iroh/src/memory.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/memory.rs)** – In-process memory lookup for testing scenarios.
- **`iroh/examples/`** – Runnable demonstrations of address lookup configuration.
- **[`iroh/tests/patchbay/util.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/tests/patchbay/util.rs)** – Test utilities showing multi-service registration and filtering.

## Summary

- **Address lookup services** enable endpoint discovery via the `AddressLookup` trait, requiring `publish` and `resolve` methods.
- **Registration** occurs during the builder phase using `Endpoint::builder().address_lookup()`, accepting both `AddressLookup` instances and `AddressLookupBuilder` implementations.
- **Multiple services** coexist within `AddressLookupServices`, which merges resolve streams and ensures all services receive filtered publish data.
- **Built-in options** include `PkarrPublisher` for pkarr relay integration, `DnsAddressLookup` for DNS resolution, and `MemoryLookup` for testing.
- **Address filtering** via `AddrFilter` allows pruning of sensitive addresses before publication to any external service.

## Frequently Asked Questions

### What is the difference between AddressLookup and AddressLookupBuilder?

**`AddressLookup`** is the runtime trait used for publishing and resolving addresses, while **`AddressLookupBuilder`** defers construction until the endpoint is fully configured. Use `AddressLookupBuilder` when your service needs to inspect the finalized endpoint configuration—such as its relay URL or socket addresses—before initializing.

### How does iroh merge results from multiple lookup services?

The **`AddressLookupServices`** registry creates a merged stream (`AddressLookupStream`) that yields items from all registered services as soon as they become available. According to the implementation in [`iroh/src/address_lookup.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup.rs), the merge logic buffers errors and continues polling other services, ensuring that a fast-failing resolver does not hide later successes from slower services, as demonstrated in the test `address_lookup_succeeds_after_other_resolver_errors`.

### Can I restrict which addresses are published to external services?

Yes. Set an **`AddrFilter`** on the endpoint builder or via `address_lookup().set_addr_filter()` after construction. This function intercepts the `EndpointData` before publication and can prune direct socket addresses, leaving only relay URLs, or reorder addresses based on your network policies.

### How do I implement a custom address lookup service for a private discovery protocol?

Implement the **`AddressLookup`** trait for your custom type, defining the `resolve` method to return a stream of `Result<Item, Error>` and `publish` to handle your protocol's advertisement mechanism. Register the instance using `Endpoint::builder().address_lookup()` or `address_lookup().add()` if the endpoint is already bound.