Hyperswarm
Topic-based peer discovery and encrypted connections on top of HyperDHT.
Hyperswarm is the high-level networking layer for discovering peers by a shared 32-byte topic and opening encrypted connections between them. Prefer one swarm instance per app and join multiple topics on that same instance when possible.
Install
npm i hyperswarmQuickstart
import Hyperswarm from 'hyperswarm'
const server = new Hyperswarm()
const client = new Hyperswarm()
server.on('connection', socket => {
socket.end('hello from the server')
})
client.on('connection', socket => {
socket.once('data', async buf => {
console.log(buf.toString())
await Promise.all([client.destroy(), server.destroy()])
})
})
const topic = Buffer.alloc(32).fill('pear-docs-topic')
const discovery = server.join(topic, { server: true, client: false })
await discovery.flushed()
client.join(topic, { server: false, client: true })
await client.flush()API Reference
Constructor and state
new Hyperswarm(opts = {})
- Signature:
const swarm = new Hyperswarm(opts) - Parameters:
opts.keyPair: Noise key pair to use for DHT listen and connect operations. Defaults to a new key pair.opts.seed: 32-byte seed used to derive a deterministic key pair.opts.maxPeers: Maximum number of peer connections to keep open.opts.firewall: Synchronous function(remotePublicKey) => booleanthat rejects a peer when it returnstrue.opts.dht: Existinghyperdhtinstance to reuse instead of creating one internally.
- Returns: A new
Hyperswarminstance. - Example:
const swarm = new Hyperswarm({ maxPeers: 32 })
await swarm.listen()swarm.connecting
- Signature:
swarm.connecting - Returns:
numbercount of outbound connections still opening. - Example:
if (swarm.connecting > 0) console.log('connecting...')swarm.connections
- Signature:
swarm.connections - Returns:
Setof active encrypted duplex connections. - Example:
for (const socket of swarm.connections) socket.write('ping')swarm.peers
- Signature:
swarm.peers - Returns:
Map<string, PeerInfo>keyed by the remote Noise public key as a hex string. - Example:
for (const [key, peer] of swarm.peers) {
console.log(key, peer.prioritized)
}swarm.dht
- Signature:
swarm.dht - Returns: The underlying
hyperdhtinstance used by the swarm. - Example:
console.log('bootstrap ready:', !!swarm.dht)Topic membership
swarm.join(topic, opts = {})
- Signature:
const discovery = swarm.join(topic, opts) - Parameters:
topic: 32-byteBufferthat identifies the swarm topic.opts.server: Announce on the DHT and accept inbound connections for this topic. Defaults totrue.opts.client: Query the DHT and connect to discovered servers for this topic. Defaults totrue.opts.limit: Maximum peers to connect to for this topic. Defaults toInfinity.
- Returns: A
PeerDiscoveryobject for the topic. - Example:
const discovery = swarm.join(topic, { server: true, client: false })
await discovery.flushed()Client mode discovers and dials servers for a topic. Server mode announces that topic and accepts inbound connections. Connections opened in client mode update peerInfo.topics; inbound server connections are not tied to a single topic.
await swarm.leave(topic)
- Signature:
await swarm.leave(topic) - Parameters:
topic: 32-byteBufferpreviously joined withswarm.join(...).
- Returns: A promise that resolves after discovery and announcement for that topic stop.
- Example:
await swarm.leave(topic)Leaving a topic stops new discovery work but does not close already-open connections.
swarm.status(topic)
- Signature:
const discovery = swarm.status(topic) - Parameters:
topic: 32-byteBufferfor a joined topic.
- Returns: The current
PeerDiscoveryfor that topic, ornullif the topic is not active. - Example:
const discovery = swarm.status(topic)
if (discovery) await discovery.refresh({ client: true, server: true })await swarm.flush()
- Signature:
await swarm.flush() - Returns: A promise that resolves after pending DHT announces complete and queued peer connections have been processed.
- Example:
swarm.join(topic, { client: true, server: false })
await swarm.flush()flush() is global to the swarm rather than scoped to one topic, so it can be comparatively expensive.
Direct peers and events
swarm.joinPeer(noisePublicKey)
- Signature:
swarm.joinPeer(noisePublicKey) - Parameters:
noisePublicKey: 32-byteBuffercontaining the remote peer's Noise public key.
- Returns: Nothing. Hyperswarm starts and maintains a direct connection attempt to that peer.
- Example:
swarm.joinPeer(remotePublicKey)swarm.leavePeer(noisePublicKey)
- Signature:
swarm.leavePeer(noisePublicKey) - Parameters:
noisePublicKey: 32-byteBufferfor a peer previously targeted withjoinPeer(...).
- Returns: Nothing. Future reconnect attempts stop.
- Example:
swarm.leavePeer(remotePublicKey)If the peer is already connected, leavePeer(...) does not close that existing socket.
swarm.on('connection', (socket, peerInfo) => {})
- Signature:
swarm.on('connection', (socket, peerInfo) => {}) - Parameters:
socket: End-to-end encrypted duplex stream for the peer connection.peerInfo:PeerInfoobject describing the connected peer.
- Returns: The swarm emits this event whenever a new peer connection opens.
- Example:
swarm.on('connection', (socket, peerInfo) => {
console.log(peerInfo.publicKey)
socket.write('hello')
})swarm.on('update', () => {})
- Signature:
swarm.on('update', () => {}) - Returns: The swarm emits this event whenever internal counters or connection state change.
- Example:
swarm.on('update', () => {
console.log(swarm.connecting, swarm.connections.size)
})swarm.on('ban', (peerInfo, err) => {})
- Signature:
swarm.on('ban', (peerInfo, err) => {}) - Parameters:
peerInfo: Banned peer metadata.err: Error describing why the peer was banned, such as a firewall rejection.
- Returns: The swarm emits this event after a peer becomes banned.
- Example:
swarm.on('ban', (peerInfo, err) => {
console.log('banned', peerInfo.publicKey, err?.message)
})Listening and lifecycle
await swarm.listen()
- Signature:
await swarm.listen() - Returns: A promise that resolves once the swarm is listening for inbound connections.
- Example:
await swarm.listen()listen() is usually called for you after the first join(...), but it is available when you want listening to start earlier.
await swarm.suspend({ log } = {})
- Signature:
await swarm.suspend({ log }) - Parameters:
log: Optional logging function used while the swarm suspends networking. Defaults to a no-op.
- Returns: A promise that resolves after peer connections, server listening, and discovery are suspended.
- Example:
await swarm.suspend({ log: console.log })await swarm.resume({ log } = {})
- Signature:
await swarm.resume({ log }) - Parameters:
log: Optional logging function used while the swarm resumes networking. Defaults to a no-op.
- Returns: A promise that resolves after the DHT, listening server, and discovery resume.
- Example:
await swarm.resume({ log: console.log })await swarm.destroy({ force } = {})
- Signature:
await swarm.destroy({ force }) - Parameters:
force: Optional boolean that skips graceful topic cleanup whentrue.
- Returns: A promise that resolves after the swarm closes its server, discovery work, and underlying DHT instance.
- Example:
await swarm.destroy()PeerDiscovery
await discovery.flushed()
- Signature:
await discovery.flushed() - Returns: A promise that resolves once a server-mode topic has been fully announced on the DHT.
- Example:
const discovery = swarm.join(topic, { server: true, client: false })
await discovery.flushed()await discovery.refresh({ client, server })
- Signature:
await discovery.refresh({ client, server }) - Parameters:
client: Optional boolean to enable or disable client lookups.server: Optional boolean to enable or disable server announcements.
- Returns: A promise that resolves after the topic configuration is refreshed.
- Example:
await discovery.refresh({ client: true, server: true })Refreshing a server-mode discovery also triggers a new DHT announcement for that topic.
await discovery.destroy()
- Signature:
await discovery.destroy() - Returns: A promise that resolves after discovery and announcements for that topic stop.
- Example:
await discovery.destroy()PeerInfo
peerInfo.publicKey
- Signature:
peerInfo.publicKey - Returns: The peer's Noise public key as a
Buffer. - Example:
console.log(peerInfo.publicKey)peerInfo.topics
- Signature:
peerInfo.topics - Returns: Array of joined topics associated with the peer when the local swarm connected in client mode.
- Example:
for (const topic of peerInfo.topics) console.log(topic)peerInfo.prioritized
- Signature:
peerInfo.prioritized - Returns:
truewhen the swarm should reconnect to the peer aggressively. - Example:
if (peerInfo.prioritized) console.log('high-priority peer')peerInfo.ban(banStatus = false)
- Signature:
peerInfo.ban(banStatus = false) - Parameters:
banStatus:trueto ban the peer orfalseto unban it.
- Returns: Nothing. Updates whether the swarm should avoid future reconnect attempts.
- Example:
peerInfo.ban(true)Banning prevents future reconnection attempts, but it does not close an already-open connection.
See also
- Connect to many peers by topic with Hyperswarm — broader topic-based discovery walkthrough.
- Connect two peers by key with HyperDHT — direct one-to-one connections without topic discovery.
- Recommended practices — why one Hyperswarm instance per app is the preferred pattern.
- HyperDHT — lower-level DHT and hole-punching layer beneath Hyperswarm.
- Secretstream — the encrypted stream type that Hyperswarm connections expose.
- Protomux — multiplex multiple protocols across one Hyperswarm connection.
- Corestore — pass swarm connections directly to
store.replicate()to co-replicate all managed cores.