Library / SDK
n0-computer/iroh avatar
n0-computer/iroh

iroh: dialing by public key instead of IP address

IP addresses break, dial keys instead. A library that adds QUIC + NAT Traversal to your apps.

12,608 stars761 forksRustApache-2.0

At a glance

What is it?
iroh is a Rust library that turns QUIC plus NAT hole-punching into a connect-to-a-key API. Here is what the workspace actually contains, how to get an echo server running, and where the relay fallback and FFI story impose real costs.
Who is it for?
Adopt iroh if you are writing Rust and your peers move between networks, because the Endpoint and Router API removes address bookkeeping you would otherwise hand-roll. Do not adopt it if your transport is not Rust and you are unwilling to go through iroh-ffi, or if you need a documented self-hosting story for the relay and DNS lookup path, which the README does not provide.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem iroh is aimed at: addresses that stop working

Most networking code assumes an address is stable. A server has a hostname, a client has an IP, and the two meet. That assumption fails the moment a peer is a phone on cellular, a laptop moving between Wi-Fi networks, or a device behind carrier-grade NAT. The README states the premise directly: iroh gives you an API for dialing by public key, and when you say "connect to that phone", iroh finds and maintains the fastest connection regardless of where it is. The audience is Rust developers building peer-to-peer or device-to-device features who do not want to write address discovery, hole-punching and relay fallback themselves. The repository also ships protocol crates for common shapes of that work: iroh-blobs for BLAKE3-based content-addressed transfer, iroh-gossip for publish-subscribe overlays, and iroh-docs for an eventually-consistent key-value store of blobs.

How the connection actually gets established

iroh does not invent a transport. It uses noq to establish QUIC connections between endpoints, which is where authenticated encryption, concurrent streams with priorities, datagrams and the absence of head-of-line blocking come from. On top of that sits the part iroh owns: a direct path is preferred, hole-punching is attempted when needed, and if that fails the connection falls back to public relay servers. The README describes this as an open ecosystem of relays and points at a continuously measured performance site, so the relay is a fallback rather than the intended steady state. The repository layout backs the claim that relays are first-class, not an afterthought: iroh-relay contains both the relay client and the server implementation, described as the code run in production for the public relays, and iroh-dns-server is the DNS server implementation powering DNS/Pkarr address lookup for EndpointIds at dns.iroh.link. That means the key-to-address resolution step is a real service with a real implementation in this repo, which is useful if you care about how a public key becomes a reachable endpoint.

Installing iroh and running the echo example

The README says it is easiest to use iroh from Rust and gives the install as a single cargo command. Everything else in this section is drawn from the echo example in the README.

bash
cargo add iroh

On the accepting side you bind an endpoint and register a protocol handler against an ALPN identifier. The ALPN string is application-defined; the example uses iroh-example/echo/0.

rust
const ALPN: &[u8] = b"iroh-example/echo/0";

let endpoint = Endpoint::bind().await?;

let router = Router::builder(endpoint)
    .accept(ALPN.to_vec(), Arc::new(Echo))
    .spawn()
    .await?;

The handler itself receives a connection and opens a bidirectional QUIC stream, copying bytes from receive to send.

rust
#[derive(Debug, Clone)]
struct Echo;

impl ProtocolHandler for Echo {
    async fn accept(&self, connection: Connection) -> Result<()> {
        let (mut send, mut recv) = connection.accept_bi().await?;
        let bytes_sent = tokio::io::copy(&mut recv, &mut send).await?;
        send.finish()?;
        connection.closed().await;
        Ok(())
    }
}

The connecting side binds its own endpoint, connects to the address with the same ALPN, opens a bidirectional stream, writes a payload, finishes the send side, and reads the echo back. The README asserts the returned bytes equal what was sent. Note the close sequence in the example: the side receiving the last application data calls conn.close, then endpoint.close tears down the endpoint and all its connections. What you should see is the echoed payload and a clean shutdown rather than a hang.

Where iroh stops being the right tool

The README is explicit that using iroh from languages other than Rust means going through iroh-ffi, a separate repository. That is a real boundary. If your application is Python, Go, or a mobile client, you are not consuming this crate directly; you are consuming a binding layer whose maturity and release cadence are not described here. The repository does not document a supported non-Rust path inside the workspace itself. The second constraint is the relay and naming infrastructure. The README says you can run the public relay code yourself, and iroh-relay is in the workspace, but there is no configuration walkthrough, no sizing guidance, and no statement about what happens to existing connections when a relay is unavailable or retired. The README does not document rollback or migration behaviour for relay changes. If your threat model requires that no third party ever sees connection metadata, the fallback path is the thing to reason about before you commit, and this material does not settle that question either way.

iroh against building on raw QUIC

The obvious alternative is using a QUIC implementation such as quinn directly, and the difference is not the transport, since iroh itself builds on noq for QUIC. The difference is what sits above it. With raw QUIC you supply a socket address to connect to, which means you own discovery, you own the decision to attempt a direct path, and you own the fallback when NAT traversal fails. iroh replaces the address with an EndpointId and moves those three responsibilities behind Endpoint::connect. That trade is favourable when peers are mobile and unfavourable when they are not: for two servers in the same datacentre with stable addresses, the relay ecosystem and DNS lookup machinery are overhead you are carrying for a problem you do not have. The other comparison worth making is within iroh's own family. If your actual task is moving content-addressed blobs, iroh-blobs already exists and the README lists it as a protocol built on iroh, so writing your own transfer protocol on top of the core Endpoint API is likely wasted effort.

Licence, release cadence and upgrade cost

The project is dual licensed under Apache-2.0 and MIT, at your option, with the copyright line reading 2025 N0, INC. The README states that contributions are dual licensed the same way unless stated otherwise, which is the standard inbound-equals-outbound arrangement. That permissive pairing is the least restrictive common choice and removes the licence question from most adoption decisions, though it says nothing about patents beyond what Apache-2.0 itself carries; that is a question for your own counsel, not something this article can answer. On upgrade cost, the workspace Cargo.toml configures cargo-semver-checks so that deprecating a struct field, enum variant, function, macro, trait associated const or global value requires at least a minor version bump. That is a meaningful signal: the maintainers are treating deprecations as breaking-ish events rather than silently shipping them in patch releases. The release history shows v1.2.0 on 2026-09-11, v1.1.0 on 2026-08-25 and v1.0.3 on 2026-07-20, so the cadence since 1.0 has been roughly monthly. The workspace also pins a release profile with LTO and panic=abort for optimized builds, which is worth knowing if you embed iroh in a binary that relies on unwinding.

What to check before you depend on it

The repository is not archived and the last push was on 2026-09-21, so this is a live codebase rather than a frozen one. The workspace splits cleanly into iroh, iroh-relay, iroh-base and iroh-dns-server, plus the iroh-dns and bench crates, which tells you the boundary between the library you depend on and the infrastructure you might have to operate. Read TRANSPORTS.md and example.config.toml in the repository root before deciding anything about relay configuration, since the README does not cover it. If your peers are Rust and your endpoints move, the API surface shown above is small enough to evaluate in an afternoon. If they are not Rust, the question you are really answering is about iroh-ffi, and that is a different repository with a different set of facts.

Editorial conclusion

Adopt iroh if you are writing Rust and your peers move between networks, because the Endpoint and Router API removes address bookkeeping you would otherwise hand-roll. Do not adopt it if your transport is not Rust and you are unwilling to go through iroh-ffi, or if you need a documented self-hosting story for the relay and DNS lookup path, which the README does not provide. Before committing, run the echo example between two machines on different networks and watch whether the connection is direct or relayed, since that distinction is the whole value proposition.

Frequently asked questions

What is iroh software?

iroh is a Rust library that gives you an API for dialing by public key rather than by IP address, finding and maintaining the fastest connection to a peer. It uses noq to establish QUIC connections and falls back to public relay servers when hole-punching fails.

Is iroh secure?

The README states that using QUIC via noq gives you authenticated encryption out of the box. It does not make any broader security claims, and the fallback to public relay servers is a design detail you should evaluate against your own threat model.

How do I install iroh in a Rust project?

The README gives the install as cargo add iroh. It notes that using iroh from Rust is the easiest path, and points to iroh-ffi for other languages.

Can I use iroh from Python or Android?

The README directs anyone wanting to use iroh from other languages to iroh-ffi, a separate repository for FFI bindings. It does not document a Python or Android path inside this workspace.

What is the difference between iroh and iroh-blobs or iroh-gossip?

iroh is the core library for hole-punching and communicating with relays. iroh-blobs, iroh-gossip and iroh-docs are protocols built on iroh that the README recommends using instead of writing your own.

Official sources

  1. License: Apache-2.0
  2. n0-computer/iroh on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/n0-computer-iroh.svg)](https://hysenlabs.com/projects/n0-computer-iroh)