Build modern peer-to-peer applications with Iroh. QUIC-based P2P networking, hole punching, content distribution, and decentralized data synchronization.
Build decentralized, peer-to-peer applications with Iroh — a modern Rust P2P library based on QUIC with automatic hole punching, relay fallback, and content distribution.
Iroh is a nextgen P2P library that implements:
Iroh represents data sovereignty: users control their own nodes, direct connections replace central servers, and data stays decentralized.
cargo new my_p2p_app
cd my_p2p_app
# Add dependencies
cargo add iroh@0.13
cargo add tokio --features full
cargo add anyhow
cargo add tracing tracing-subscriber
use anyhow::Result;
#[tokio::main]
async fn main() -> Result<()> {
// Spawn an Iroh node with all services
let node = iroh::node::Builder::default()
.spawn()
.await?;
println!("✅ P2P node started!");
println!(" 📦 Blobs: Available");
println!(" 📝 Docs: Available");
println!(" 💬 Gossip: Available");
// Keep running
println!("\n⏳ Running... (Ctrl+C to stop)");
tokio::signal::ctrl_c().await?;
println!("👋 Shutting down...");
Ok(())
}
cargo build --release
./target/release/my_p2p_app
Every Iroh node has a node ID (public key) that other peers can connect to:
// Access node ID through services
let node_id = node.blobs.node_id().await?;
println!("My node ID: {}", node_id);
// Share this with other peers to establish connections
Iroh provides modular services you can use independently:
Transfer files/blobs between peers (KB to TB):
// Publish a blob
let hash = node.blobs.add_bytes(b"Hello, P2P!").await?;
// Access via peer's node ID
let peer_id = "..."; // from other peer
let content = node.blobs.get_bytes(hash).await?;
Sync structured data between peers with conflict-free resolution:
// Create a document (CRDT-based)
let doc = node.docs.create().await?;
// Write data
doc.set_bytes(b"key", b"value").await?;
// Other peers auto-sync
Broadcast messages across a P2P network (publish/subscribe):
// Subscribe to a topic
let topic = "alerts".as_bytes();
let mut sub = node.gossip.subscribe(topic.clone()).await?;
// Publish a message
node.gossip.publish(topic.clone(), b"New alert!").await?;
// Receive messages
while let Ok(msg) = sub.next().await {
println!("Received: {}", String::from_utf8_lossy(&msg));
}
Connect to a peer by their node ID:
// Dial a peer directly
let peer_id = "..."; // node ID of another peer
let connection = node.net.connect(peer_id).await?;
// Use connection for RPC, streaming, etc.
Use Iroh's DHT (Distributed Hash Table) for peer discovery:
// Announce your content
let hash = node.blobs.add_bytes(data).await?;
// Other peers query DHT to find providers
// Iroh handles this automatically
When direct connections fail (firewall), Iroh falls back to relays:
// Configured automatically - no code needed
// If direct connection fails → relay takes over
// User experiences seamless P2P
// Peer A: Share a file
let path = "/path/to/file.txt";
let bytes = std::fs::read(path)?;
let hash = node.blobs.add_bytes(&bytes).await?;
println!("Share this hash: {}", hash);
// Peer B: Receive the file
let hash = "..."; // from Peer A
let bytes = node.blobs.get_bytes(hash).await?;
std::fs::write("/path/to/downloaded.txt", bytes)?;
// Create shared document
let doc = node.docs.create().await?;
// Publish document ID via gossip
let doc_id = doc.id().to_string();
node.gossip.publish(b"shared_docs", doc_id.as_bytes()).await?;
// All peers subscribe and sync the doc
// Concurrent edits merge automatically (CRDT)
// Cache data in blobs, announce via gossip
let cache_entry = serde_json::to_vec(&data)?;
let hash = node.blobs.add_bytes(&cache_entry).await?;
// Broadcast availability
node.gossip.publish(b"cache_updates", hash.as_ref()).await?;
// Peers can fetch via hash
Iroh handles NAT traversal automatically:
// Your node automatically:
// ✓ Detects if behind NAT (via STUN)
// ✓ Attempts hole punching
// ✓ Falls back to relays if needed
// → No manual configuration required
Choose a storage backend:
// In-memory (default, for testing)
let node = iroh::node::Builder::default()
.spawn()
.await?;
// Persistent storage (recommended)
let node = iroh::node::Builder::default()
.data_dir("/path/to/data")
.spawn()
.await?;
Use public relays (can self-host):
// Iroh provides public relays
// Or run your own relay:
// https://github.com/n0-computer/iroh/tree/main/iroh-relay
All Iroh connections use TLS 1.3 with perfect forward secrecy:
// No extra code needed - automatic
Peers are identified by their node ID (public key):
// Only trust specific peer IDs
let trusted_peer = "...";
if connection.peer_id() == trusted_peer {
// Process message
}
Implement application-level authorization:
// Docs can have per-key permissions
doc.set_bytes_with_author(
author_key,
key,
value,
).await?;
// Iroh uses Quinn (QUIC implementation)
// Sensible defaults for most use cases
// Customize if needed:
// - Connection timeout
// - Max streams
// - MTU size
// Efficient blob operations
let hashes = futures::stream::iter(data)
.then(|item| async move {
node.blobs.add_bytes(&item).await
})
.collect::<Vec<_>>()
.await;
// Use content hashes for deduplication
// Same content = same hash → no duplication
let hash1 = node.blobs.add_bytes(b"data").await?;
let hash2 = node.blobs.add_bytes(b"data").await?;
assert_eq!(hash1, hash2); // Same content address
# Run multiple nodes locally for testing
# Terminal 1
RUST_LOG=debug cargo run -- --bind 127.0.0.1:0
# Terminal 2
RUST_LOG=debug cargo run -- --bind 127.0.0.1:0
# Nodes discover and connect automatically via DHT
#[tokio::test]
async fn test_p2p_transfer() {
let node_a = iroh::node::Builder::default().spawn().await.unwrap();
let node_b = iroh::node::Builder::default().spawn().await.unwrap();
// Transfer data between nodes
let data = b"test data";
let hash = node_a.blobs.add_bytes(data).await.unwrap();
let retrieved = node_b.blobs.get_bytes(hash).await.unwrap();
assert_eq!(retrieved, data);
}
| Pattern | Use Case | Example | |---------|----------|---------| | Blob Transfer | File sync, backups | Share files without server | | Doc Sync | Collaborative editing | Real-time document updates | | Gossip | Notifications, feeds | Broadcast events to all peers | | Hybrid | Complex apps | Combine all three services |
Usually means relay fallback is needed:
// Iroh handles this automatically
// Check logs: RUST_LOG=debug
// If persistent, peer may be offline
Could be relay usage (slower than direct):
# Check direct connection vs relay
RUST_LOG=iroh_net=debug
# Look for "direct" vs "relay" in logs
Blobs are content-addressed and immutable:
// Remove old blobs manually if needed
node.blobs.remove(hash).await?;
iroh-basics/ — Simple node initializationiroh-blobs/ — Content distribution patternsiroh-docs/ — Document sync exampleiroh-gossip/ — Broadcasting exampleiroh-full-app/ — Complete app with all servicesIroh enables true data sovereignty:
This is the foundation of nextgen protocols: decentralized, user-controlled infrastructure.
This skill connects to the K-Dense-AI/claude-scientific-skills ecosystem:
distributed-systems: 3 citations in bib.duckdbThis skill connects to Software Design for Flexibility (Hanson & Sussman, 2021):
Concepts: redundancy, fallback, multiple strategies, robustness
iroh-p2p (−) + SDF.Ch8 (−) + [balancer] (−) = 0
Skill Trit: -1 (MINUS - verification)
Degeneracy provides fallbacks. This skill offers redundant strategies.
This skill maps to Cat# = Comod(P) as a bicomodule in the equipment structure:
Trit: 0 (ERGODIC)
Home: Prof
Poly Op: ⊗
Kan Role: Adj
Color: #26D826
The skill participates in triads satisfying:
(-1) + (0) + (+1) ≡ 0 (mod 3)
This ensures compositional coherence in the Cat# equipment structure.
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer