Skip to content
minip2p
Esc
navigateopen⌘Jpreview
On this page

React Native quickstart

Install @minip2p/react-native, create a development build, and connect from a component.

@minip2p/react-native requires React Native 0.87 with the New Architecture and Hermes. It supports iOS 15.1 or newer and Android API 24 or newer.

Install

npm install @minip2p/react-native

Allow local-network connections

On iOS, a direct connection to the desktop on the LAN needs a local-network usage description. For Expo, merge this into app.json or the equivalent app config before rebuilding:

{
  "expo": {
    "ios": {
      "infoPlist": {
        "NSLocalNetworkUsageDescription": "Connect to a peer on your local network."
      }
    }
  }
}

For a bare React Native app, set NSLocalNetworkUsageDescription in the native iOS app’s Info.plist instead.

On Android, ensure the host android/app/src/main/AndroidManifest.xml declares INTERNET. The standard React Native template already includes it:

<uses-permission android:name="android.permission.INTERNET" />

Rebuild the application after installation. Expo Go cannot load minip2p, so an Expo SDK 57 app needs a development build:

npx expo install expo-dev-client
npx expo prebuild
npx expo run:ios
# or: npx expo run:android

Connect to a Node.js listener

useMinip2p owns the endpoint for a component. It starts the endpoint after the component commits and closes it during cleanup.

First, run the listener from the Node.js quickstart. Its default listener uses 127.0.0.1, which is reachable only from the desktop itself. Change listener.mjs to bind the desktop’s LAN address, for example /ip4/192.168.1.42/udp/4001/quic-v1, then restart it. Copy the complete address it prints:

/ip4/192.168.1.42/udp/4001/quic-v1/p2p/12D3KooW...

Do not give the phone the original 127.0.0.1 address. It names the phone itself. Put the phone and desktop on the same LAN, avoid a guest network that isolates devices, and allow incoming UDP port 4001 through the desktop’s firewall.

Put this in App.tsx for a project without Expo Router, or in the route component for an Expo Router project. Replace the placeholder string in remoteAddress with the complete address printed by the running listener:

import { generateSecretKey, useMinip2p } from "@minip2p/react-native";
import { useCallback, useMemo, useState } from "react";
import { Button, Text, View } from "react-native";

const remoteAddress = "YOUR_LISTENER_ADDRESS_HERE";

export default function App() {
  const secretKey = useMemo(() => generateSecretKey(), []);
  const createConfig = useCallback(
    () => ({
      agentVersion: "my-app/0.1.0",
      secretKey,
    }),
    [secretKey]
  );
  const node = useMinip2p(createConfig);
  const [result, setResult] = useState("Not connected");

  const connect = useCallback(async () => {
    if (node.status !== "running") return;

    try {
      const connected = await node.endpoint.connectAddr(remoteAddress, {
        timeoutMs: 10_000,
      });
      await node.endpoint.waitPeerReady(connected.peerId, {
        timeoutMs: 10_000,
      });
      const rttMs = await node.endpoint.ping(connected.peerId, {
        timeoutMs: 5_000,
      });
      setResult(`${connected.path.kind} · ${rttMs} ms`);
    } catch (error) {
      setResult(error instanceof Error ? error.message : String(error));
    }
  }, [node, remoteAddress]);

  if (node.status === "starting") return <Text>Starting minip2p...</Text>;
  if (node.status === "failed") return <Text>Failed: {String(node.error)}</Text>;
  if (node.status === "closed") return <Text>Endpoint closed</Text>;

  return (
    <View>
      <Text selectable>{node.peerId}</Text>
      <Text selectable>{node.listenAddrs.join("\n")}</Text>
      <Button title="Connect and ping" onPress={() => void connect()} />
      <Text>{result}</Text>
    </View>
  );
}

Keep createConfig pure and stable for the component lifetime. Store the secret bytes in protected device storage when the peer needs a stable identity.

Open the screen on the phone, tap “Connect and ping,” and allow local-network access if iOS prompts. The result shows directDialed and the round-trip time, such as directDialed · 4 ms.

Prepare mDNS permissions

If the app enables mdns: true, add its Bonjour service type on iOS and the multicast permissions on Android. Merge the Expo settings into the same app config, keeping the usage description above. Bare iOS apps add the service to Info.plist instead.

{
  "expo": {
    "ios": {
      "infoPlist": {
        "NSBonjourServices": ["_p2p._udp"]
      }
    }
  }
}
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />

Rebuild after changing either file.

Next: Endpoint lifecycle or Networking and events.

Last updated on September 7, 2026

Was this page helpful?