A minimal libp2p implementation in Rust: small, portable, understandable, and pleasant to use.
minip2p is built around a few deliberate constraints:
- Protocol and orchestration logic is Sans-I/O and deterministic.
- Core crates support
no_std + alloc. - There is no
async/.await; callers choose the executor and drive progress. - QUIC is the only transport adapter.
unsafeis forbidden across the workspace.
The result is a set of reusable protocol state machines and a synchronous
Endpoint API for applications that want sensible defaults.
Install minip2p:
[dependencies]
minip2p-rs = "0.3.0"The package is named minip2p-rs on crates.io and imported as minip2p:
use minip2p::{Deadline, Endpoint, Event};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut endpoint = Endpoint::builder()
.agent_version("my-app/0.1.0")
.bind_quic_dual_stack()?;
for address in endpoint.listen_all()? {
println!("listening on {address}");
}
while let Some(event) = endpoint.next_event(Deadline::NEVER)? {
println!("{event:?}");
if matches!(event, Event::ConnectionEstablished { .. }) {
// Open streams, ping the peer, or continue polling for events.
}
}
Ok(())
}Endpoint is caller-driven: it owns sockets, but it does not start a runtime or
background task. Event waits accept an absolute Instant, a relative
Duration, or Deadline::NEVER.
For a complete application, run the gossipsub chat example:
cargo run -p minip2p-chat -- host --nick hostessSee the chat guide for NAT and cross-implementation recipes. The peer example demonstrates relay reservations and direct-path upgrades with DCUtR.
The base Endpoint includes QUIC, multistream-select, identify, ping, and
application protocols registered with EndpointBuilder::protocol.
| Feature | Adds |
|---|---|
nat |
Circuit Relay v2, AutoNAT, and DCUtR traversal policy |
pubsub |
StrictSign gossipsub by default, with explicit floodsub selection |
discovery |
Signed pubsub presence beacons and coordinated dialing; implies nat and pubsub |
mdns |
Local-link discovery and coordinated direct dialing; implies nat |
Features layer onto the same API. Lower-level users can instead drive
SwarmCore and individual protocol crates directly with explicit inputs,
outputs, timestamps, and deadlines.
The workspace has three strictly separated layers:
- Sans-I/O protocols — identity, TLS, Noise, Yamux, multistream-select, ping, identify, relay, AutoNAT, DCUtR, pubsub, and mDNS. These crates contain state machines and wire codecs, not sockets or clocks.
- Sans-I/O orchestration —
SwarmCore,NatAgent,BeaconAgent, andPeerDiscoveryAgentcompose protocols and policy while remaining deterministic and I/O-free. stdadapters — the quiche-based QUIC transport, mDNS socket driver, application-facingEndpoint, and UniFFI adapter own real I/O.
The default swarm intentionally includes only identify, ping, and registered application protocols. Relay, traversal, pubsub, and discovery policy stay opt-in so the base remains small and predictable.
TypeScript bindings live under bindings/ts: @minip2p/core defines the
platform-neutral API, and @minip2p/react-native provides its UniFFI-backed
React Native implementation. The Node adapter is currently a private scaffold.
Every crate has its own README with API-specific details.
just commands mirror CI:
just test # workspace tests and Endpoint feature matrix
just clippy # warnings-as-errors, feature variants, and fuzz crate
just fmt # format the workspace and fuzz crate
just check-nostd # no_std crates on thumbv7em-none-eabi
just bench
just fuzz 30 # requires nightly and cargo-fuzzGenerate local API documentation with:
cargo doc --workspace --no-deps --openAll published Rust and TypeScript packages share one version. Releases also include freshly built Android and iOS libraries for React Native.