How to Contribute to the iroh Project: A Complete Developer’s Guide

Start with a discussion or issue in the n0-computer/iroh repository, fork and branch from main, implement your changes in the appropriate Rust crate, and submit a draft pull request following the guidelines in CONTRIBUTING.md.

The iroh project is a Rust-based peer-to-peer networking stack built on QUIC, providing hole-punching, relay services, and DNS resolution. Contributing to this open-source repository requires understanding its modular workspace architecture and adhering to the structured workflow defined by the maintainers. Whether you are fixing a bug or adding a new feature, knowing how to navigate the crate structure ensures your contribution lands smoothly.

Understand the iroh Workspace Architecture

The iroh repository is organized as a Cargo workspace containing multiple specialized crates. Understanding which crate owns specific functionality prevents circular dependencies and ensures code lands in the correct location.

Core Library and Supporting Crates

  • iroh – The core library located in iroh/src/lib.rs that exposes the public API for hole-punching and connection establishment.
  • iroh-relay – Implements the relay client and server logic in iroh-relay/src/server.rs for public relay nodes.
  • iroh-base – Contains shared types like EndpointId and RelayUrl in iroh-base/src/lib.rs used across the workspace.
  • iroh-dns and iroh-dns-server – Provide DNS-based address lookup (Pkarr) for endpoint IDs, with source in iroh-dns/src/lib.rs.
  • Workspace Configuration – The top-level Cargo.toml defines all workspace members and build profiles.

Step-by-Step Contribution Workflow

The project follows a well-defined contribution workflow documented in CONTRIBUTING.md. Adhering to these steps ensures your changes align with project standards and receive timely review.

  1. Discuss: Open a thread on the GitHub Discussions page to clarify scope or bounce ideas before writing code.

  2. File an Issue: Search existing issues for duplicates. If none exist, create a new issue describing the bug or feature, optionally labeling it as feature or bug using the repository templates.

  3. Fork and Clone: Fork the repository via the GitHub interface, then clone your fork locally:

    git clone https://github.com/<your-username>/iroh.git
    cd iroh
  4. Create a Branch: Use descriptive branch names that indicate the purpose, such as feat/socket-metrics or fix/connection-timeout:

    git checkout -b feat/socket-metrics
  5. Implement the Change: Modify code in the appropriate crate (e.g., iroh/src/socket/metrics.rs). Follow Rust documentation conventions and ensure your changes do not introduce circular dependencies between crates.

  6. Write Tests: Add unit tests alongside your implementation and integration tests under iroh/tests/ or the relevant crate's test directory. Run cargo test to verify functionality.

  7. Open a Draft Pull Request: Push your branch and open a PR marked as a draft to signal work-in-progress. The PR template requires a description, breaking change notes, and a completion checklist including self-review and documentation updates.

  8. Review and Merge: Respond to reviewer feedback, iterate on the code, and mark the PR as "Ready for review" once stable. Approved contributions are merged into the main branch.

Practical Example: Adding Socket Metrics

Consider contributing a feature that tracks active QUIC streams per socket. This example demonstrates where to place code and how to test it within the workspace structure.

Implementing the Metrics Struct

Add the following to iroh/src/socket/metrics.rs to track socket statistics:

/// Tracks basic socket statistics.
#[derive(Default, Debug, Clone)]
pub struct SocketMetrics {
    /// Current number of open QUIC streams.
    pub open_streams: usize,
}

impl SocketMetrics {
    /// Increment the open-stream counter.
    pub fn inc_streams(&mut self) {
        self.open_streams += 1;
    }

    /// Decrement the open-stream counter.
    pub fn dec_streams(&mut self) {
        self.open_streams = self.open_streams.saturating_sub(1);
    }
}

Exposing the Public API

In iroh/src/socket.rs, provide a public accessor method:

impl Socket {
    /// Return a copy of the current metrics.
    pub fn metrics(&self) -> SocketMetrics {
        self.metrics.clone()
    }
}

Integration Testing

Create iroh/tests/socket_metrics.rs to verify the functionality:

#[tokio::test]
async fn test_socket_metrics() {
    let endpoint = iroh::Endpoint::bind().await.unwrap();
    let socket = endpoint.socket(); // hypothetical accessor
    let mut metrics = socket.metrics();

    // Simulate opening two streams.
    metrics.inc_streams();
    metrics.inc_streams();
    assert_eq!(metrics.open_streams, 2);

    // Simulate closing one stream.
    metrics.dec_streams();
    assert_eq!(metrics.open_streams, 1);
}

Run the test suite with cargo test to validate your implementation.

Essential Files for Contributors

Before contributing, familiarize yourself with these key files in the n0-computer/iroh repository.

CONTRIBUTING.md

The CONTRIBUTING.md file at the repository root contains the complete contribution workflow, PR style guide, and review checklist. This is the primary reference for submission standards.

README.md

README.md provides the high-level project description, lists all workspace crates, and outlines licensing information.

Workspace Configuration

The top-level Cargo.toml lists all workspace members and defines global build profiles. Consult this file to understand crate dependencies and feature flags.

Core Source Files

Summary

  • The iroh project is a Rust workspace split into specialized crates including iroh, iroh-relay, iroh-base, and iroh-dns.
  • Always start contributions by discussing changes in GitHub Discussions or filing an issue to avoid duplicate work.
  • Follow the 8-step workflow: discuss, issue, fork, branch, implement, test, draft PR, and review.
  • Place code in the appropriate crate (e.g., iroh/src/ for core features, iroh-relay/src/ for relay logic) to avoid architectural conflicts.
  • Reference CONTRIBUTING.md for the complete style guide and submission checklist.

Frequently Asked Questions

Do I need to sign a Contributor License Agreement (CLA) to contribute to iroh?

The source analysis does not mention a CLA requirement. According to the repository guidelines in CONTRIBUTING.md, contributors should follow the standard GitHub fork-and-pull workflow. Review the README.md for specific licensing terms, as the project typically requires contributions under the existing open-source license.

Which crate should I modify to fix a bug in hole-punching logic?

Hole-punching and connection establishment logic resides in the iroh crate, specifically within iroh/src/lib.rs and related socket modules. For changes to how endpoints interact with relay servers, you may also need to modify iroh-relay in iroh-relay/src/server.rs.

How do I run tests before submitting my contribution?

Execute cargo test from the workspace root to run the full test suite. For faster iteration, run tests for a specific crate using cargo test -p iroh or target specific integration tests in iroh/tests/. Ensure all tests pass and your code follows rustfmt standards before marking your PR as ready for review.

Can I contribute documentation improvements without writing code?

Yes. Documentation contributions follow the same workflow: file an issue describing the gap, fork the repository, and edit the relevant .md files or Rust doc comments. Open a draft PR with your changes, ensuring examples compile and links remain valid. The maintainers welcome improvements to both the API documentation and high-level guides.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →