---
title: Feature matrix
description: Compare Rust feature activation and TypeScript SDK configuration with the network infrastructure each capability needs.
---

## Rust

Cargo features control what code is available. Builder methods control what runs inside an endpoint. External network infrastructure determines which paths are actually usable.

| Capability | Cargo selection | Builder activation | Active behavior | Infrastructure |
| --- | --- | --- | --- | --- |
| Direct QUIC, Identify, Ping, custom streams | Default (`std`, `quic`) | None required | Authenticated QUIC streams and built-in protocols | A mutually reachable UDP path |
| Direct TCP | `tcp` | `.listen_on("/ip4/0.0.0.0/tcp/4001")?` or `.listen_on_multiaddr(...)` with a `/tcp` address | Noise-authenticated Yamux streams over TCP | A mutually reachable TCP path |
| Portable TCP | `default-features = false, features = ["smoltcp"]` | `Endpoint::portable(...).smoltcp(...).listen(...).build()` | TCP, Noise XX, Yamux, Identify, Ping, and custom streams on a caller-driven loop | Your smoltcp device, interface, clock, and entropy |
| Reachability probing | `autonat` | `.autonat_server(server)` or a `NatConfig` with probe servers | AutoNAT probes and reachability state | Reachable AutoNAT server |
| Relayed connections and DCUtR | `relay` (DCUtR needs `quic` too) | `.relay(relay)` or relay-bearing `.nat_config(...)` | Reservations, relay races, and hole punching | Reachable Circuit Relay v2 server |
| Gossipsub | `pubsub` | `.gossipsub()` or gossipsub `.gossipsub_config(...)` | Signed gossipsub messages | At least one compatible mesh peer |
| Signed discovery | `discovery` (includes `pubsub`) | `.discovery()` or `.discovery_config(...)` | Signed beacons, shared peer book, and optional automatic dialing | A connected discovery peer; relay optional for direct-only addresses |
| Local-link discovery | `mdns` | `.mdns()` or `.mdns_config(...)` | Local observations, shared peer book, and optional automatic dialing | Multicast-capable local network and interface |

## Default std API

The default dependency selection enables `std` and `quic`. `Endpoint` and `EndpointBuilder` require `std`; the QUIC methods below also require `quic`.

Available on the std `Endpoint`:

- Address publication: `listen`, `listen_all`
- Connection attempts: `connect`, `cancel_connect`, `disconnect`
- State snapshots: `peer_id`, `connected_peers`, `is_peer_ready`, `peer_info`, `connection_id`, `connection_remote_addr`, `connection_info`, `path`, `bound_addresses`
- Streams: `add_protocol`, `open_stream` (returns the connection and stream IDs), `send_stream`, `close_stream_write`, `reset_stream`, `abandon_stream` (each addressed by connection and stream ID), and `StreamWriter` for whole writes with a deferred close
- Ping: `ping` (RTT arrives as `EndpointEvent::PingRttMeasured`)
- Driving: blocking `wait` (every event, including capability variants, or the deadline, or an interruption); non-blocking `poll`; `wait_handle` to interrupt a blocked `wait`
- Identify advertisement: `set_external_addresses`
- Shutdown: `close`

Available on `EndpointBuilder` with `quic`:

- Listen: `listen_on`, `listen_on_multiaddr` with `/udp/<port>/quic-v1` addresses (at most one per IP family), `listen_default` (dual-stack QUIC wildcards), then `bind`
- Configuration: `quic_limits`

`EndpointBuilder::bind` is available with `std`, but needs at least one listen address (otherwise it fails with `BindError::Options(EndpointOptionsError::NoTransport)`). Enable `quic` or `tcp` before listening on a corresponding address.

## TCP API

Compiled with `features = ["tcp"]`:

- Listen: `listen_on`, `listen_on_multiaddr` with `/tcp/<port>` addresses
- Configuration: `tcp_config` (connection, buffer, timeout and Yamux limits)
- Routing: QUIC addresses use QUIC; `/tcp` candidates use TCP

## Portable API

With default features off, `Endpoint::portable(identity, entropy)` starts a `PortableEndpoint` builder. Call `build(transport)` with any caller-provided `Transport`. The resulting endpoint runs the same engine and event order as the std `Endpoint`, but uses `poll(now)` and `next_deadline(now)` instead of the blocking `wait`; Connection attempts use `connect(target, now)` and `cancel_connect(id, now)`, and `poll(now)` returns `Vec<EndpointEvent>`, including enabled capability variants. It never reads a system clock or starts a runtime, and it has no raw swarm access.

Capabilities are builder setters behind the same features as the std `Endpoint`'s, over any transport: `pubsub` (Gossipsub), `discovery` (signed beacons), `mdns` (`.mdns(io, config)` over any `MdnsIo`, `.peer_discovery_config(..)`), `autonat`, `relay`, and `relay-server`. Relays need circuit operations: build with `build_with_circuits` over a `CircuitTransport`; `build` refuses relay configuration. Portable endpoints do not run DCUtR, so relays need `NatConfig::dcutr = false` or `force_relay`.

The `smoltcp` feature adds a shared embedded TCP stack and includes portable mDNS; `.smoltcp(stack)` builds TCP and mDNS on it and returns the same `PortableEndpoint`.

## NAT API

Compiled with `features = ["autonat"]`, or `["relay"]`, which includes it:

- Activation: `autonat_server`, `nat_config`; with `relay`, `relay`
- Configuration: with `relay`, `circuit_limits` (relay circuits' Yamux limits)
- Attempts: `connect` races direct candidates against a relay leg; `cancel_connect`
- Events: `EndpointEvent::Nat(..)` via `wait` or `poll`
- State: `reachability`; with `relay`, `active_reservation`

`bind` refuses NAT configuration that cannot run with `BindError::NatConfig`: no relay or AutoNAT server, a reservation policy other than `Never` without a relay, or relays with DCUtR on an endpoint built without `quic`. `.autonat_server(..)` alone holds no reservation.

> **Warning**
>
> An AutoNAT server enables reachability probing but does not supply a relay path. Configure a relay for circuits, reservations, and relay-assisted DCUtR.

## Pubsub API

Compiled with `features = ["pubsub"]`:

- Activation: `gossipsub`, `gossipsub_config`
- Topics: `subscribe`, `unsubscribe`, `publish`
- Events: `EndpointEvent::Gossipsub(..)` via `wait` or `poll`

## Discovery API

Compiled with `features = ["discovery"]`, which includes the `pubsub` Cargo feature:

- Activation: `discovery`, `discovery_config`
- Shared policy: `peer_discovery_config`
- State: `known_peers`
- Events: `EndpointEvent::Discovery(..)` via `wait` or `poll`

Activating discovery also activates default pubsub, and, when `autonat` or `relay` is compiled in, the NAT agent with no servers so discovered peers go through the connect race. A relay remains optional for direct discovery, but required for relayed paths and relay-assisted punching.

## mDNS API

Compiled with `features = ["mdns"]`, which does not include `pubsub`:

- Activation: `mdns`, `mdns_config`
- Shared policy: `peer_discovery_config`
- State: `known_peers`
- Events: `EndpointEvent::Discovery(..)`, plus `EndpointEvent::MdnsFailed { error }` / `MdnsRecovered` for socket failures, via `wait` or `poll`
- mDNS lifecycle: `shutdown` sends goodbyes and stops mDNS without closing the endpoint, returning `Result<(), MdnsError>`

mDNS discovers peers only on multicast-capable local links. Its address claims remain unauthenticated until the selected transport verifies the peer identity. Automatic mDNS-triggered attempts are direct-only and never activate a configured relay or HOP CONNECT. A socket failure while running does not stop mDNS: it is reported as `MdnsFailed`, retried after `MDNS_FAILURE_RETRY` (100 ms), and followed by `MdnsRecovered` once a retry works. `Endpoint::shutdown` sends TTL-zero goodbyes and permanently stops mDNS; QUIC and TCP keep working. With both `discovery` and `mdns` enabled, both sources use one bounded peer book and one automatic-dial state.

## TypeScript

Node.js and React Native accept the same `Minip2pConfig`. It selects the capabilities and infrastructure used by an endpoint.

| Capability | Configuration | Active behavior | Infrastructure |
| --- | --- | --- | --- |
| Direct QUIC/TCP, Identify, Ping, custom streams | `secretKey`; optional `listen` (complete multiaddresses) and `protocols` | `Minip2p.create` starts the endpoint; without `listen` it binds dual-stack QUIC only | A mutually reachable UDP or TCP path |
| Gossipsub | Always on | Signed outbound pubsub and strict inbound validation | At least one compatible mesh peer |
| Signed discovery | `discovery: { topic, ... }` | Signed beacons, shared peer book, optional auto-dial | A connected discovery peer |
| Local-link discovery | `mdns: true` or options | mDNS, shared peer book, optional auto-dial | A multicast-capable local network; mobile hosts also need local-network permissions |
| Reachability probing | `autonatServers: [...]` | AutoNAT probes | Reachable AutoNAT server |
| Relayed paths and DCUtR | `relays: [...]` | Reservations, relay race, fallback, hole punching | Reachable Circuit Relay v2 server |

An AutoNAT server still does not provide a relay path. Discovery and mDNS can dial advertised direct addresses without a relay. See [Networking and events](/docs/typescript/networking-and-events) for configuration examples, and the [TypeScript API](/docs/reference/typescript-api) reference for the full configuration map.

## Full Rust API

[docs.rs publishes the Rust API for the latest release](https://docs.rs/minip2p-rs/latest/minip2p/). That reference uses the default `std` and `quic` features. Check the [published feature list](https://docs.rs/crate/minip2p-rs/latest/features) for the optional flags.

Generate the default rustdoc locally:

```bash
cargo doc -p minip2p-rs --no-deps --open
```

To include every optional std feature in one local build:

```bash
cargo doc -p minip2p-rs --features relay,discovery,mdns,tcp,relay-server --no-deps --open
```

For the `no_std + alloc` view, disable defaults. Add the portable features your application uses, for example:

```bash
cargo doc -p minip2p-rs --no-default-features --features smoltcp,discovery,relay --no-deps --open
```
