iroh Endpoint Builder Pattern and Configuration Options: A Complete Guide
The iroh::endpoint::Builder implements a chainable builder pattern that collects optional network, identity, and transport settings and finalizes them into a live Endpoint through a single bind call.
The iroh crate in the n0-computer/iroh repository exposes its core networking primitive via the Endpoint type, configured through the builder API defined in iroh/src/endpoint.rs. Understanding the iroh Endpoint builder pattern and its configuration options is essential for customizing peer-to-peer connections, whether you need to tweak socket binding, swap crypto providers, or disable relay fallback entirely.
How the iroh Endpoint Builder Pattern Works
An Endpoint requires a large amount of runtime information, including crypto providers, transport configuration, and relay settings. The iroh::endpoint::Builder holds a partial configuration and exposes a chainable API so you can override only the values you care about.
You create the builder through Endpoint::builder(preset), passing a preset such as presets::N0 or presets::Empty. Each configuration method takes &mut self and returns Self, enabling fluent chaining. When you are ready, Builder::bind validates the collected state—for example, ensuring a crypto provider is present—and then constructs the actual networking resources.
Core Endpoint Builder Configuration Options
As implemented in iroh/src/endpoint.rs, the builder surfaces methods across several functional categories. Below are the key chainable methods and what they control.
Preset Initialization
new(preset),preset(preset),empty()— Initialize the builder with a bundled configuration or start from a clean slate. For example,presets::N0selects a default crypto provider, relay map, and DNS/PKARR address-lookup services, whilepresets::Emptyleaves every option unset.
Network Transports and Socket Binding
bind_addrandbind_addr_with_opts— Bind the endpoint to specific IP sockets.bind_addr_with_optsaccepts aBindOptsstruct for advanced control such as prefix length.clear_ip_transportsandclear_relay_transports— Remove the built-in IPv4/IPv6 or relay transports so you can define custom behavior.
The underlying transport primitives are defined in iroh/src/socket/transports.rs, and socket allocation is handled by iroh/src/socket/bind.rs.
Identity and Application Protocols
secret_key— Set the secret key that determines the endpoint’sEndpointId. If omitted,bindgenerates one automatically.alpns— Provide a list of ALPN identifiers the endpoint will accept during connection negotiation.
Relay Configuration and Address Discovery
relay_mode— Choose a relay strategy:Default,Staging,Custom, orDisabled. This controls whether and how the endpoint uses relay servers for NAT traversal.address_lookup,clear_address_lookup,addr_filter,clear_addr_filter,user_data_for_address_lookup— Register or remove services that publish and discover the endpoint’s addresses, such as PKARR and DNS. Trait definitions for these services live iniroh/src/address_lookup/mod.rs.external_addr— Manually advertise additional publicly reachable socket addresses beyond those discovered automatically.
Transport Tuning, DNS, and Proxy Settings
transport_config— Override the defaultQuicTransportConfigto adjust max streams, flow-control windows, and other QUIC parameters.dns_resolver(non-WASM targets only) — Supply a custom DNS resolver for relay hostnames and address lookups.proxy_urlandproxy_from_env— Force all HTTP(S) traffic, including relay communication, through a proxy server.ca_tls_config— Set trusted CA certificates for TLS connections to relays or DoH resolvers.keylogandmax_tls_tickets— Enable TLS pre-master-key logging for debugging and adjust the TLS ticket cache size.
Crypto Providers, Hooks, and Advanced Extensions
crypto_provider— Select the Rustls crypto implementation, such asringoraws-lc-rs. This is required unless a crate feature supplies a default.hooks— Install anEndpointHooksimplementation to intercept connection establishment events.portmapper_config— Enable or disable UPnP, PCP, and NAT-PMP for automatic gateway port mapping.net_report_config— Tune the optional net-report component that probes relays to detect NAT behavior, latency, and captive portals.add_custom_transport(unstable feature) — Register a user-defined transport implementation.path_selector(unstable feature) — Replace the default biased-RTT path selector with a custom algorithm.
What Builder::bind Does Under the Hood
When you invoke bind, the builder executes a strict validation and construction sequence defined in iroh/src/endpoint.rs:
- Generates a
SecretKeyif you did not provide one viasecret_key. - Validates that a
crypto_provideris present; otherwise, construction fails. - Builds TLS server and client configs, a QUIC
StaticConfig, and a socket options struct from the accumulated state. - Calls
socket::EndpointInner::bindto allocate sockets and start the underlying QUIC endpoint. - Installs address-lookup services and applies any address filter you configured.
This encapsulation keeps the public Endpoint API clean while ensuring that every fully built instance is in a valid state.
Practical iroh Endpoint Builder Examples
Default N0 Preset
The presets::N0 preset bundles a crypto provider, a default relay map, and standard DNS/PKARR address-lookup services. It is the fastest way to spin up an endpoint:
use iroh::{Endpoint, endpoint::presets};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let ep = Endpoint::builder(presets::N0).bind().await?;
println!("Running as {}", ep.id().fmt_short());
Ok(())
}
This example uses Endpoint::builder followed immediately by bind, relying entirely on the N0 defaults defined in iroh/src/endpoint/presets.rs.
Custom Transports and ALPN
To bind specific addresses and restrict accepted protocols, start from presets::Empty and layer on exactly what you need:
use iroh::{Endpoint, endpoint::presets, endpoint::BindOpts};
use std::sync::Arc;
let ep = Endpoint::builder(presets::Empty)
.crypto_provider(Arc::new(rustls::crypto::ring::default_provider()))
.clear_ip_transports()
.bind_addr_with_opts("127.0.0.1:0", BindOpts::default().set_prefix_len(24))?
.bind_addr_with_opts("[::1]:0", BindOpts::default().set_prefix_len(48))?
.alpns(vec![b"my-protocol".to_vec()])
.bind()
.await?;
Here, clear_ip_transports removes defaults before bind_addr_with_opts attaches IPv4 and IPv6 listeners. The alpns call restricts the endpoint to a single application protocol.
Custom Address Lookup Service
You can integrate your own address discovery logic by implementing the AddressLookupBuilder trait and registering it with the builder:
struct MyLookup;
impl iroh::address_lookup::AddressLookupBuilder for MyLookup {
fn into_address_lookup(
self,
_ep: &iroh::Endpoint,
) -> Result<
Box<dyn iroh::address_lookup::AddressLookup>,
iroh::address_lookup::AddressLookupFailed,
> {
// ...implementation...
todo!()
}
}
let ep = Endpoint::builder(presets::Minimal)
.address_lookup(MyLookup)
.bind()
.await?;
The builder stores this service and installs it during bind so the endpoint can publish or resolve addresses through your custom backend.
Disable Relays for Direct Connections
If your deployment guarantees direct IP connectivity, disable relay fallback entirely:
let ep = Endpoint::builder(presets::Minimal)
.relay_mode(iroh::RelayMode::Disabled)
.clear_relay_transports()
.bind()
.await?;
Setting relay_mode to RelayMode::Disabled and clearing relay transports ensures the endpoint never attempts relayed communication.
Summary
- The
iroh::endpoint::Builderimplements a classic builder pattern iniroh/src/endpoint.rs, collecting partial configuration through chainable methods and producing a finalizedEndpointviabind. - Presets such as
presets::N0supply sensible defaults, whilepresets::Emptylets you opt into every setting manually. - Key configuration areas include socket binding,
secret_keyandalpns,relay_mode,address_lookupservices,transport_config, andcrypto_provider. - The
bindmethod validates required state—especially the crypto provider—generates missing secrets, builds TLS/QUIC internals, and starts the socket layer insidesocket::EndpointInner::bind.
Frequently Asked Questions
What is the difference between presets::N0 and presets::Empty?
presets::N0 bundles a default crypto provider, relay map, and DNS/PKARR address-lookup services so you can call bind immediately. presets::Empty starts from a blank slate, requiring you to manually configure the crypto provider, transports, and any discovery logic before the endpoint can start.
Is crypto_provider always required when using the iroh Endpoint builder?
Yes, a crypto provider must be present before bind succeeds. If you use a preset like N0 that includes one, or if a crate feature supplies a default, you do not need to call crypto_provider explicitly. Otherwise, you must set it yourself.
Can I run an iroh endpoint without any relay servers?
Yes. Call .relay_mode(iroh::RelayMode::Disabled) and .clear_relay_transports() on the builder. This removes relay fallback and forces the endpoint to rely solely on direct IP connections.
How does Builder::bind validate configuration before spawning the endpoint?
Inside iroh/src/endpoint.rs, bind first ensures a crypto_provider is present and generates a SecretKey if none was supplied. It then constructs TLS and QUIC configurations, calls socket::EndpointInner::bind to open sockets, and finally installs any address-lookup services and filters. If any required state is missing, construction fails before network resources are allocated.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →