# What Is the Store Module in iroh?

> Discover the critical role of the iroh store module, the persistence and caching layer for pkarr. It manages signed packet storage, intelligent caching, and mainline DHT fallback resolution.

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

---

**The store module in iroh serves as the central persistence and caching layer for the DNS-based pkarr (public-key address record) system, handling signed packet storage, intelligent caching, and mainline DHT fallback resolution.**

The `store` module is a critical component of the `iroh-dns-server` crate, powering the infrastructure behind iroh's decentralized name resolution. Located in [`iroh-dns-server/src/store.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns-server/src/store.rs), this module provides durable storage for pkarr records while maintaining high-performance access patterns through intelligent caching mechanisms. It bridges local Redb-backed persistence with the global mainline DHT network to resolve queries efficiently.

## Core Responsibilities of the iroh Store Module

The store module encapsulates five primary functions that enable robust pkarr-based DNS resolution.

### Persisting Signed Packets

At the foundation of the store module lies the **SignedPacketStore** implementation found in [`iroh-dns-server/src/store/signed_packets.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns-server/src/store/signed_packets.rs). This component writes pkarr signed packets to a durable **Redb** database, ensuring data survives server restarts.

The `ZoneStore` struct provides two initialization patterns:

- **`ZoneStore::persistent`** – Opens a disk-backed database at a specified path for production deployments.
- **`ZoneStore::in_memory`** – Creates a transient store for testing scenarios or fast-startup requirements.

The store handles packet insertion via `ZoneStore::insert` and retrieval through `ZoneStore::get_signed_packet`, maintaining data integrity across both storage modes.

### Caching for Fast Look-ups

To minimize disk I/O on repeated queries, the store module maintains a **ZoneCache** with two distinct cache layers:

- **`ZoneCache::cache`** – An LRU (Least Recently Used) cache for the most recently accessed zones, providing sub-millisecond access to hot data.
- **`ZoneCache::dht_cache`** – A TTL-based cache specifically for entries fetched from the mainline DHT, preventing stale data from persisting indefinitely.

This dual-cache architecture ensures that frequently requested records remain in memory while DHT-fetched entries respect their time-to-live constraints.

### Resolving DNS Queries

The `ZoneStore::resolve` method serves as the primary entry point for DNS resolution. This method accepts a public key, domain name, and record type, then executes a hierarchical lookup strategy:

1. Checks the LRU cache for immediate hits.
2. Falls back to the persistent Redb store for local zones.
3. Queries the mainline DHT if the zone remains unknown locally.

Upon success, the method returns a `RecordSet` that the DNS server serializes directly back to the client.

### Mainline DHT Fallback

When local storage lacks a requested zone, the store module can leverage the global **mainline DHT** network. By configuring the store with `with_mainline_fallback`, the `ZoneStore` obtains a DHT client capable of querying the distributed hash table.

The fallback mechanism searches for the most recent mutable pkarr item, converts it to a `SignedPacket`, inserts it into the cache for future requests, and resolves the original DNS query transparently.

### Metrics and Background Eviction

The store module integrates comprehensive telemetry through the shared `Metrics` struct, tracking packets inserted, updates processed, and cache evictions. A background eviction task runs continuously, removing packets older than the configured `Options::eviction` duration to prevent unbounded storage growth.

## Key Source Files and Architecture

The store module spans several files within the `iroh-dns-server` crate:

| File | Description |
|------|-------------|
| [`iroh-dns-server/src/store.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns-server/src/store.rs) | Core `ZoneStore` implementation containing persistence logic, caching strategies, DHT fallback, and resolution algorithms. |
| [`iroh-dns-server/src/store/signed_packets.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns-server/src/store/signed_packets.rs) | Low-level Redb-backed storage for signed packets, including background eviction and snapshot handling. |
| [`iroh-dns-server/src/server.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns-server/src/server.rs) | DNS server initialization that constructs the `ZoneStore` and wires it into the request handling pipeline. |
| [`iroh-dns-server/src/dns.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns-server/src/dns.rs) | High-level DNS request handling that delegates resolution to `ZoneStore::resolve`. |
| [`iroh-dns-server/src/state.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns-server/src/state.rs) | Runtime state management holding the `ZoneStore` instance used by the server. |
| [`iroh-dns-server/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns-server/src/lib.rs) | Public API exposing `ZoneStore`, `Options`, and `PacketSource` for external integration. |

## Working with the Store Module

### Creating a Persistent Store

The following example demonstrates initializing a persistent `ZoneStore` and resolving a DNS query:

```rust
use iroh_dns_server::{
    store::{Options, PacketSource, ZoneStore},
    metrics::Metrics,
};
use std::sync::Arc;

// Initialize shared metrics
let metrics = Arc::new(Metrics::default());

// Open persistent storage
let store = ZoneStore::persistent(
    "./data/pkarr.db",
    Options::default(),
    metrics.clone(),
)?;

// Resolve a query
let pubkey = PublicKeyBytes::from_hex("...")?;
let name = Name::from_ascii("example.iroh.")?;
let record_type = RecordType::A;

match store.resolve(&pubkey, &name, record_type).await? {
    Some(record_set) => println!("Found records: {:?}", record_set),
    None => println!("No matching records"),
}

```

### Using In-Memory Storage with DHT Fallback

For testing or lightweight deployments, combine in-memory storage with DHT resolution:

```rust
let store = ZoneStore::in_memory(Options::default(), metrics.clone())?
    .with_mainline_fallback(BootstrapOption::default());

// Insert a signed packet from a pkarr publish operation
store.insert(signed_packet, PacketSource::PkarrPublish).await?;

```

## Summary

- The **store module** in [`iroh-dns-server/src/store.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns-server/src/store.rs) provides the backbone for pkarr-based DNS resolution in the iroh ecosystem.
- **ZoneStore** supports both persistent Redb storage and in-memory modes, selectable via `persistent()` or `in_memory()` constructors.
- Dual-layer caching (LRU for hot data, TTL-based for DHT entries) optimizes query performance while preventing stale data retention.
- The `resolve()` method implements a hierarchical lookup: cache → disk → mainline DHT, ensuring maximum record availability.
- Background eviction and comprehensive metrics collection maintain storage bounds and operational visibility.

## Frequently Asked Questions

### What database does the iroh store module use?

The store module uses **Redb** (a pure-Rust embedded key-value database) for persistent storage of signed packets. This is implemented in [`iroh-dns-server/src/store/signed_packets.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns-server/src/store/signed_packets.rs) through the `SignedPacketStore` struct, which handles all disk I/O operations and transaction management.

### How does the store module handle cache expiration?

The store module employs two distinct expiration strategies. The LRU cache (`ZoneCache::cache`) evicts least-recently used entries when capacity limits are reached, while the DHT cache (`ZoneCache::dht_cache`) uses TTL (time-to-live) values to automatically expire stale entries fetched from the distributed hash table.

### What is the difference between `ZoneStore::persistent` and `ZoneStore::in_memory`?

`ZoneStore::persistent` opens a Redb database at a specified filesystem path, ensuring data survives server restarts and providing durability for production deployments. `ZoneStore::in_memory` creates a transient storage backend suitable for unit tests, development environments, or scenarios requiring fast startup without disk dependencies.

### How does the store module integrate with the mainline DHT?

When configured with `with_mainline_fallback`, the `ZoneStore` queries the mainline DHT for unknown zones, retrieves the most recent mutable pkarr item, converts it to a `SignedPacket`, and inserts it into the local cache. This fallback mechanism ensures the DNS server can resolve globally published records even when they are not stored locally.