# How Iroh Handles Data Synchronization: CRDT Replication Over QUIC

> Discover how Iroh synchronizes data using CRDT replication over QUIC. Explore its peer-to-peer protocol with automatic hole-punching and relay fallback.

- Repository: [number zero/iroh](https://github.com/n0-computer/iroh)
- Tags: deep-dive
- Published: 2026-07-12

---

**Iroh implements data synchronization through a peer-to-peer CRDT-style replication protocol using the iroh-sync engine, which gossips document changes over QUIC connections with automatic hole-punching and relay fallback.**

Iroh's approach to data synchronization centers on the `iroh-sync` engine, a decentralized replication system built into the main `iroh` crate according to the n0-computer/iroh source code. This engine enables real-time document synchronization across peers using conflict-free replicated data types (CRDTs) over QUIC transport, combining content-addressed storage with gossip-based peer discovery to achieve low-latency replication without central servers.

## The Iroh-Sync Architecture

### Document-Level Stores and CRDT Semantics

At the core of iroh's data synchronization are **documents**—mutable key-value stores that function as CRDTs. As implemented in [`iroh/src/sync/mod.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/sync/mod.rs), each document tracks changes as *entries* containing the author's public key, a monotonically increasing name-stamp, and a timestamp. This structure ensures that concurrent modifications converge correctly without coordination, allowing peers to write offline and synchronize later.

### Content-Addressed Blob Storage

Documents are backed by `iroh-blobs`, a content-addressed blob store integrated into the sync engine. When a peer learns about new blob hashes through synchronization, the engine requests missing blobs from whichever peer already holds them. The sync engine tracks *content hashes* per document, iterates over them efficiently, and streams the data to remote peers as needed.

## Peer Discovery and Gossip Protocol

### Gossip-Based Peer Advertisement

Iroh-sync uses a lightweight gossip layer to advertise the existence of documents and negotiate sync sessions. The gossip protocol propagates *peer data*—the set of peers that know about a given document—and *neighbor events* that drive the sync engine's state machine. This enables dynamic membership where peers can join and leave without disrupting document consistency.

### Content-Hash Propagation

Rather than broadcasting full document contents, the synchronization process focuses on propagating content hashes. When changes occur, the gossip layer announces new hashes, allowing peers to pull only missing data. This approach minimizes bandwidth usage and leverages the content-addressed nature of the underlying storage in `iroh-blobs`.

## Connection Establishment and Transport

### QUIC Hole-Punching and Relay Fallback

All synchronization traffic runs over QUIC connections established by the core Iroh endpoint. The system first attempts direct QUIC hole-punching as implemented in [`iroh/src/endpoint/bind.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/bind.rs). If NAT traversal fails, iroh falls back to the public relay network using address lookup logic in [`iroh/src/address_lookup/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/pkarr.rs). The sync actor attaches directly to the QUIC connection, enabling the sync protocol to start immediately once the channel opens.

### Sync Actor Lifecycle

The sync actor manages replication session lifecycles automatically. According to the source code in [`iroh/src/sync/mod.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/sync/mod.rs), the actor starts when a document is opened and shuts down cleanly when the iroh node exits. Inactive replicas are automatically pruned to conserve resources, and read-only replicas can be created without pulling the full blob history.

## Implementation Example

The following code demonstrates how to set up data synchronization using the public API from the `iroh` crate:

```rust
use iroh::sync::{self, SyncEngine};
use iroh::doc::Document;
use iroh::endpoint::Endpoint;
use std::sync::Arc;

// 1️⃣  Create a QUIC endpoint that will be used for all connections.
let endpoint = Endpoint::bind().await?;

// 2️⃣  Open (or create) a document that we want to keep in sync.
let doc = Document::open("my-doc").await?;

// 3️⃣  Build the sync engine – it automatically discovers peers via gossip.
let sync = SyncEngine::builder()
    .endpoint(endpoint.clone())
    .document(doc.clone())
    .build()
    .await?;

// 4️⃣  Start the sync engine (runs in the background).
let sync_handle = sync.spawn();

// 5️⃣  Write a value to the document; the sync engine will propagate it.
doc.put("hello", b"world").await?;

// 6️⃣  Later we can shut down the engine cleanly.
sync_handle.shutdown().await?;

```

This example showcases the three main steps: **endpoint creation**, **document opening**, and **sync engine instantiation**. After the engine is running, any changes made to the document are automatically gossiped to peers that have announced interest in the same document.

## Key Implementation Files

- **[`iroh/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs)** – Re-exports the public Iroh API, including the sync module.
- **[`iroh/src/sync/mod.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/sync/mod.rs)** – Core implementation of the sync engine, gossip handling, and document store.
- **[`iroh/src/endpoint/quic.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/quic.rs)** – QUIC connection handling that underpins all peer-to-peer traffic.
- **[`iroh/src/endpoint/bind.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/bind.rs)** – Endpoint creation and hole-punching logic.
- **[`iroh/src/address_lookup/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/pkarr.rs)** – Public-relay address lookup used when hole-punching fails.

## Summary

- Iroh's data synchronization relies on the **iroh-sync engine**, which implements CRDT-style replication over QUIC connections.
- **Documents** are mutable key-value stores backed by content-addressed blob storage, tracking entries with author keys, name-stamps, and timestamps.
- **Gossip-based discovery** advertises document availability and propagates content hashes rather than full data, optimizing bandwidth.
- **Connection resilience** comes from QUIC hole-punching with automatic fallback to relay networks via `pkarr` address lookup.
- The **sync actor** manages lifecycle automatically, pruning inactive replicas and supporting read-only modes without full history.

## Frequently Asked Questions

### What is the iroh-sync engine?

The iroh-sync engine is the core replication system within the `iroh` crate that implements a peer-to-peer CRDT protocol. It manages document synchronization by tracking content hashes, gossiping changes to interested peers, and coordinating data transfer over QUIC connections established through the iroh endpoint.

### How does iroh handle NAT traversal during synchronization?

Iroh attempts direct QUIC hole-punching first using logic in [`iroh/src/endpoint/bind.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/bind.rs). If direct connection fails, it automatically falls back to the public relay network, resolving relay addresses through [`iroh/src/address_lookup/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/pkarr.rs). This ensures synchronization works across NATs and firewalls without manual configuration.

### What data structure does iroh use for synchronized documents?

Iroh uses **documents**—mutable key-value stores that act as CRDTs. Each change is stored as an entry containing the author's public key, a monotonically increasing name-stamp, and a timestamp. These entries reference content-addressed blobs in `iroh-blobs`, allowing efficient incremental synchronization.

### How does iroh manage memory for inactive replicas?

The sync engine automatically prunes inactive replicas to conserve resources. Additionally, read-only replicas can be created without pulling the full blob history, allowing peers to participate in synchronization with minimal storage overhead. The sync actor handles these lifecycle transitions transparently when documents open and close.