Iroh 1.0: Dial Keys, Not IPs — A Deep Dive Into the P2P Networking Stack
For as long as the internet has existed, connecting two devices has meant knowing where they are. You need an IP address, and that address has to be reachable. But IP addresses are a leaky abstraction: they change when your phone hops from WiFi to cellular, they hide behind NATs and firewalls, and they are handed to you by a network you do not control. The moment your device moves, the address breaks — and there is nothing you can do about it.
On June 15, 2026, a small company called n0 shipped the 1.0 release of iroh, a networking library built on a deceptively simple inversion of that model: dial keys, not IPs. Instead of asking "what is the address of that device," you say "connect me to that device" — identified by its public key — and iroh finds and maintains the fastest connection for you, wherever it is. This post is a technical deep dive into how that works, what shipped in 1.0, and why it matters.
The core idea: a key is a better address than an IP
The pitch fits on a sticker: IP addresses break, dial keys instead. But the consequences run deep.
A public key has properties an IP address never will. You create it and you control it — no ISP or cloud provider assigns it to you. It stays the same as your device roams across networks. You can throw it away when you are done, or keep it forever. And critically, the same key that names a device can also secure the connection to it. Once every byte on the wire is bound to that key, you can build identity, permissions, and attribution up from the same primitive. As n0 puts it, dialing by key "turns the internet into a secure localhost."
That last phrase is the whole thesis. On localhost, connections just work — they are direct, instant, and you do not think about routers or addresses. Iroh is an attempt to make any two devices on Earth feel like they are on the same machine.
This is not a research prototype. The numbers from the 1.0 announcement are worth sitting with: the public relays n0 operates have seen more than 200 million endpoints created in the last 30 days alone, and iroh is "running on millions of devices today." It took 65 releases over more than four years of building in the open to get to this first stable version.
How a connection actually gets made
The elegance of the dial-by-key abstraction hides a genuinely hard networking problem underneath: how do you establish a direct connection between two devices when both are buried behind NATs and firewalls? Iroh's answer is a layered strategy that always prefers the fast path and degrades gracefully when it cannot get it.
1. Discovery. Before iroh can connect to a key, it has to find a candidate address for it. It resolves the public key (an EndpointId) into network locations using a DNS-based system — n0 runs a Pkarr/DNS server at dns.iroh.link for exactly this — though discovery is pluggable and can also work over local mDNS for devices on the same LAN.
2. Hole-punching for a direct path. The fastest route is always a direct device-to-device connection, so iroh tries to hole-punch through the NATs on both sides. When it succeeds — which it does remarkably often — traffic never touches a server. n0 reports that it is normal to see 95% of the data in a connection pass directly between devices. Fewer hops through the cloud means a lower egress bill for you, and fewer hops through routers means a more efficient internet overall.
3. Relay fallback. Some network topologies are simply too hostile to hole-punch through. When a direct path cannot be established, iroh falls back to an open ecosystem of public relay servers that forward the encrypted traffic. The relay is never a single point of failure or a privacy hole — it only sees ciphertext — and the connection transparently upgrades to a direct path later if one becomes available. The relay binaries are open source, so you can run your own, and n0 offers hosted relays as a paid service.
The result is a connection that just works: secure by default, direct whenever physically possible, and resilient when it is not.
Built on QUIC — and on n0's own QUIC implementation
Under the hood, iroh speaks QUIC, the transport protocol that also underpins HTTP/3. This is a deliberate and consequential choice. QUIC gives iroh authenticated encryption, multiple concurrent streams with priorities, a datagram transport, and freedom from head-of-line blocking — all of it standard, none of it bolted on.
What is more unusual is that iroh 1.0 runs on noq, n0's own implementation of QUIC written in Rust. Building your own QUIC stack is not a decision anyone makes lightly, but it unlocked the two features that make iroh's connection model possible:
- QUIC multipath. A single iroh connection can build and manage multiple network routes at once and hot-swap between them as conditions change. Your phone moving from WiFi to cellular does not drop the connection — it migrates paths underneath it. This is the machinery that makes a key-as-address actually durable across network changes.
- QUIC NAT traversal. Iroh implements NAT traversal as part of the QUIC layer itself, so it can establish direct connections while keeping the connection details encrypted. The hole-punching is not a side channel; it is part of the protocol.
n0 has been deliberate about standards here, preferring IETF drafts wherever possible rather than inventing proprietary extensions — multipath and NAT traversal both track in-progress IETF work. That matters for a project asking you to bet your application's networking on it.
What "1.0" actually guarantees
Plenty of projects slap a 1.0 on a version number. For a networking library, the version that matters is the one two strangers' devices have to agree on. Iroh 1.0 makes a concrete, load-bearing promise here:
An iroh v1 endpoint can communicate with any other iroh v1 endpoint — regardless of minor version or language.
This is wire stability, and it is the single most important thing about the 1.0 release. It means you can ship an app today, and a device running a future iroh v1.5 in Python will still talk to a device running iroh v1.0 in Rust. n0 has committed that any change that breaks wire compatibility will only ever happen in a major version bump. They even leave room to version the language API and the wire protocol independently — a v2 of the Rust API could keep speaking v1 on the wire.
Backing that up is a published support policy: major and minor versions are supported on a schedule, and the public relays will be kept current (usually within 24 hours of a release), with wire-breaking relay changes getting new URLs so older clients keep working. For anyone who has been burned by a networking dependency rearranging its protocol underneath a shipped product, this is the part of the announcement that earns trust.
The headline feature: official Python, Node.js, Swift, and Kotlin support
For most of its life, iroh was easiest to use from Rust, and an earlier attempt at foreign-function-interface (FFI) bindings was paused because keeping bindings in sync with a churning pre-1.0 API was too expensive to maintain. n0 promised to bring FFI back once the API stabilized — and 1.0 is them following through.
iroh 1.0 ships official bindings for Python, Node.js, Swift, and Kotlin, in addition to the core Rust crate. The practical impact is large: you can now embed iroh directly into an iOS app via Swift, an Android app via Kotlin, a backend service in Node, or a data pipeline in Python — all speaking the same wire protocol, all able to dial each other by key. The dial-by-key abstraction stops being a Rust-only superpower and becomes available to the platforms where most apps actually live.
Compose protocols instead of writing your own
Iroh's networking core gives you a secure, addressable connection. But most applications need more than a raw pipe — they need to move files, sync state, or broadcast events. Rather than make you build those from scratch, iroh exposes an ecosystem of ready-made protocols that compose on top of the same connection abstraction:
- iroh-blobs — content-addressed blob transfer built on BLAKE3 hashing, scaling from kilobytes to terabytes. Because content is addressed by its hash, transfers are verifiable and resumable: you always know you got exactly the bytes you asked for.
- iroh-gossip — publish-subscribe overlay networks that scale down to the resources an average phone can handle. This is how you broadcast events by topic across a swarm of devices without a central broker.
- iroh-docs — an eventually-consistent key-value store layered on iroh-blobs, for multi-device state sync.
You can pull in a pre-built protocol, or implement your own ProtocolHandler on top of the clean stream abstraction. This composability is a big part of why iroh shows up in such wildly different applications.
What it looks like in code
Here is the canonical iroh example — an echo protocol — straight from the official repository. The connecting side dials an address and an ALPN (the application-protocol identifier), opens a bidirectional QUIC stream, and sends some bytes:
const ALPN: &[u8] = b"iroh-example/echo/0";
let endpoint = Endpoint::bind().await?;
// Open a connection to the accepting endpoint
let conn = endpoint.connect(addr, ALPN).await?;
// Open a bidirectional QUIC stream
let (mut send, mut recv) = conn.open_bi().await?;
// Send some data to be echoed
send.write_all(b"Hello, world!").await?;
send.finish()?;
// Receive the echo
let response = recv.read_to_end(1000).await?;
assert_eq!(&response, b"Hello, world!");
// As the side receiving the last application data — say goodbye
conn.close(0u32.into(), b"bye!");
// Close the endpoint and all its connections
endpoint.close().await;
The accepting side binds an endpoint, registers a handler for the ALPN, and echoes whatever it receives back down the same stream:
let endpoint = Endpoint::bind().await?;
let router = Router::builder(endpoint)
.accept(ALPN.to_vec(), Arc::new(Echo))
.spawn()
.await?;
// The protocol definition:
#[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?;
// Echo any bytes received back directly.
let bytes_sent = tokio::io::copy(&mut recv, &mut send).await?;
send.finish()?;
connection.closed().await;
Ok(())
}
}
Notice what is not here: there is no STUN server configuration, no TURN credentials, no ICE candidate gathering, no certificate management. The Endpoint and Router abstractions absorb the entire NAT-traversal-and-fallback dance described earlier. You define a protocol by its bytes-in, bytes-out behavior and let iroh handle getting those bytes between two machines that may be on opposite sides of the planet behind hostile NATs.
Where iroh is already running
The most convincing argument for a networking stack is the range of things people build on it. From n0's own accounting and public case studies, iroh is already in production across a strikingly diverse set of domains:
- Distributed AI training and agents. Developers use iroh to train large language models across machines and to let agents talk to each other — direct device-to-device links avoid routing every gradient or message through a cloud relay.
- Real-time video streaming. Iroh combined with Media-over-QUIC is being used for low-latency video, including a notably pointed n0 blog post titled "What if your security camera was secure?"
- Payments at the edge. Paycode used iroh to connect payment terminals directly to point-of-sale systems at highway toll booths — with no additional servers and full PCI compliance, because the connection is direct and end-to-end encrypted.
- Embedded and microcontrollers. Iroh has been demonstrated running on an ESP32 microcontroller — the same dial-by-key stack on a chip that costs a few dollars.
- Anonymous connections. Because iroh supports custom transports, you can route iroh connections through Tor, combining the privacy of onion services with iroh's performance.
- Secure chat, file sync, and games. Direct, encrypted, address-independent connections are a natural fit for messaging, peer-to-peer file transfer, and multiplayer games.
The breadth is the point. A toll booth, a security camera, a $3 microcontroller, and a distributed LLM training run are about as far apart as networked applications get — and they all reduce to the same primitive: dial a key, get a secure connection.
Custom transports: beyond the internet
One of the quieter but more radical capabilities in 1.0 is custom transports. Iroh's dial-by-key abstraction does not actually require the internet. n0 has built hooks that let you plug in alternative ways of moving bytes — Bluetooth Low-Energy (BLE), WiFi Aware, LoRa (under construction), or even Tor — and all of them fit under the same dial-by-key API. A device can find and connect to a local peer with no internet access at all, using iroh's local-first configurations.
This is what makes "secure localhost" more than a slogan. Whether two devices are in the same room over Bluetooth or on opposite continents over the public internet, the application code is identical: you dial a key and you get a connection. The transport underneath becomes an implementation detail.
How the repository is organized
For anyone wanting to read the source, the main iroh repository is a Rust workspace of focused crates:
iroh— the core library for hole-punching and communicating with relays.iroh-relay— the relay client and server implementation. This is the exact code n0 runs in production for the public relays, and you can run it too.iroh-base— common types likeEndpointIdandRelayUrl.iroh-dns-server— the DNS server powering the Pkarr/DNS address lookup forEndpointIds, running in production atdns.iroh.link.
The composable protocols (iroh-blobs, iroh-gossip, iroh-docs), the QUIC implementation (noq), and the FFI bindings (iroh-ffi) live in their own repositories under the same n0-computer organization. The whole stack is dual-licensed under Apache-2.0 and MIT.
The verdict: a real foundation, shipped
It is easy to be cynical about "the future of the internet" framing — the peer-to-peer space is littered with ambitious projects that never reached production. What makes iroh different is that the production usage came first and the 1.0 came after: 200 million endpoints a month, millions of devices, and four years of releases before anyone claimed stability.
The 1.0 release is not about new features so much as a promise: a stable wire protocol, a stable API across five languages, and a support schedule you can plan around. For a networking library, that promise is the product. If you have ever fought with STUN/TURN servers, watched a WebRTC connection mysteriously fail behind a corporate NAT, or paid a cloud egress bill to relay traffic that should have gone direct, iroh's pitch will land: stop addressing devices by where they happen to be, and start addressing them by who they are.
The time to build, as n0 says, is now.
Sources
iroh (core):
- Repository: https://github.com/n0-computer/iroh (Apache-2.0 / MIT, ⭐~9.0k)
- Official site & docs: https://www.iroh.computer/docs
- 1.0 announcement: https://www.iroh.computer/blog/v1 ("Iroh 1.0 — Dial Keys, not IPs", June 15, 2026, by b5)
- v1.0.0 release: https://github.com/n0-computer/iroh/releases/tag/v1.0.0 (published 2026-06-15)
- Key crates inspected:
iroh(core hole-punching + relay),iroh-relay,iroh-base,iroh-dns-server
Composable protocols & dependencies:
- iroh-blobs (BLAKE3 content-addressed transfer): https://github.com/n0-computer/iroh-blobs
- iroh-gossip (pub-sub overlay): https://github.com/n0-computer/iroh-gossip
- iroh-docs (eventually-consistent KV store): https://github.com/n0-computer/iroh-docs
- noq (n0's QUIC implementation): https://github.com/n0-computer/noq
- iroh-ffi (Python/Node/Swift/Kotlin bindings): https://github.com/n0-computer/iroh-ffi
- BLAKE3: https://github.com/BLAKE3-team/BLAKE3
Case studies referenced (n0 blog):
- "iroh for payments" (Paycode toll-booth terminals), March 26, 2026
- "Running iroh on an ESP32", March 24, 2026
- "Use iroh with Tor for anonymous connections", January 27, 2026
- "What if your security camera was secure?", March 11, 2026