Skip to content

Libraries

Hyperswarm

Discovers peers on shared topics and establishes encrypted connections.

Verified 19 October 2026

Find another instance of your notes app and connect its replication stream.

Status in Unstoppable Stack

Discovery does not grant permission. Use application pairing and grants for access control.

How it works

A topic is a 32-byte discovery identifier. Peers looking for the same topic can find one another without your own application directory server.

The connection event supplies an encrypted byte stream. Your protocol still needs framing, validation and a decision about which remote identities may access data.

This example creates two peers and a local DHT bootstrap in one process. It exercises topic discovery without announcing anything to the public network.

Run an example

Use Node 22.17+ and npm for installation. Start in a new directory for this example so its ./data storage cannot collide with another example. Save each file below with the exact filename shown, then run the commands in order.

bash
mkdir hyperswarm-demo
cd hyperswarm-demo
npm init -y
npm install hyperswarm@'^4.17.2' hyperdht@'^6.34.1'

Save as example.mjs:

js
import Hyperswarm from 'hyperswarm'
import DHT from 'hyperdht'
import { randomBytes } from 'node:crypto'
const seed = DHT.bootstrapper(49777, '127.0.0.1')
await seed.ready()
const bootstrap = [{ host: '127.0.0.1', port: seed.address().port }]
const host = new Hyperswarm({ bootstrap })
const client = new Hyperswarm({ bootstrap })
const topic = randomBytes(32)
let timer
try {
  host.on('connection', socket => {
    socket.on('error', () => {})
    socket.end('Hello topic')
  })
  const received = new Promise((resolve, reject) => {
    timer = setTimeout(() => reject(new Error('Discovery timed out')), 10000)
    client.on('connection', socket => {
      let text = ''
      socket.on('data', chunk => { text += chunk.toString() })
      socket.on('end', () => resolve(text))
      socket.on('error', reject)
    })
  })
  // Start discovery and await the message together so failures are observed.
  const discovery = (async () => {
    await host.join(topic, { server: true, client: false }).flushed()
    client.join(topic, { server: false, client: true })
  })()
  const [message] = await Promise.all([received, discovery])
  console.log(message)
} finally {
  clearTimeout(timer)
  await Promise.all([host.destroy(), client.destroy()])
  await seed.destroy()
}

Run from this example directory:

bash
node example.mjs

Expected result

Hello topic

Example verification

The code shown here ran successfully in a local check on 19 October 2026. This verifies the small example, not production readiness, public-network reachability or every platform.

API essentials

  • join(topic, { server, client }): announce, discover, or do both. Await the discovery handle's flushed() when announcement must finish first.
  • on('connection', socket): handle a peer stream; attach error handling and define an application protocol.
  • destroy(): close swarm activity during shutdown. Leaving a topic alone does not close existing connections.

Troubleshooting and limits

  • Run one networking demo at a time: the local bootstrap uses UDP port 49777. Change it if that port is occupied.
  • Discovery timeout: local UDP may be blocked. The example stops waiting after ten seconds and cleans up its swarms.
  • A shared topic is not authorization. Use the P2P runtime's grants and invites for permissioned app services.
  • For a real multi-process app, share the topic explicitly and persist identities. This random topic is only shared in memory.

Next steps

Need help? Report an issue with your CLI version, platform, command and first relevant error.