HyperDHT
P2P DHT for keyed peer lookup, hole punching, and encrypted direct connections.
HyperDHT is the lower-level keyed connection layer underneath Hyperswarm. Use it when you want to dial a known public key directly or work with raw DHT discovery and record APIs.
Install
npm i hyperdhtQuickstart
import DHT from 'hyperdht'
import { once } from 'node:events'
const serverNode = new DHT()
const clientNode = new DHT()
const keyPair = DHT.keyPair()
const server = serverNode.createServer(socket => {
socket.end('hello from hyperdht')
})
await server.listen(keyPair)
const socket = clientNode.connect(keyPair.publicKey)
await once(socket, 'open')
socket.write('ping')
for await (const chunk of socket) {
console.log(chunk.toString())
}
await server.close()
await Promise.all([serverNode.destroy(), clientNode.destroy()])API Reference
Node setup
new DHT([options])
- Signature:
const node = new DHT([options]) - Parameters:
options.bootstrap: Optional array of bootstrap nodes. In Pear apps this defaults toPear.config.dht.bootstrap; elsewhere it defaults to the public HyperDHT bootstrap nodes.options.keyPair: Optional default key pair used byserver.listen()andnode.connect().options.connectionKeepAlive: Optional default socket keep-alive in milliseconds. Defaults to5000; setfalseto disable it.options.randomPunchInterval: Optional punch interval in milliseconds. Defaults to20000.- Any additional options are forwarded to
dht-rpc.
- Returns: A new
DHTnode instance. - Example:
import DHT from 'hyperdht'
const node = new DHT({
bootstrap: ['203.0.113.10:49737'],
connectionKeepAlive: 10000
})DHT.keyPair([seed])
- Signature:
const keyPair = DHT.keyPair([seed]) - Parameters:
seed: Optional seed value when you want deterministic key generation.
- Returns: An object with
publicKeyandsecretKeybuffers. - Example:
const keyPair = DHT.keyPair()
console.log(keyPair.publicKey)DHT.bootstrapper(port, host, [options])
- Signature:
const bootstrapNode = DHT.bootstrapper(port, host, [options]) - Parameters:
port: UDP port for the bootstrap node.host: Hostname or IP address to bind to.options: Optional bootstrap-node settings.
- Returns: A DHT bootstrap node for isolated or self-hosted networks.
- Example:
const bootstrapNode = DHT.bootstrapper(49737, '0.0.0.0')Servers
node.createServer([options], [onconnection])
- Signature:
const server = node.createServer([options], [onconnection]) - Parameters:
options.firewall(remotePublicKey, remoteHandshakePayload): Optional predicate that returnsfalseto accept a connection ortrueto reject it.onconnection: Optional handler that runs for each accepted socket.
- Returns: A HyperDHT server that accepts encrypted
NoiseSecretStreamconnections. - Example:
const server = node.createServer((socket) => {
socket.write('connected')
})await server.listen(keyPair)
- Signature:
await server.listen(keyPair) - Parameters:
keyPair: The{ publicKey, secretKey }pair the server should announce and accept connections on.
- Returns: A promise that resolves when the server is listening.
- Example:
const keyPair = DHT.keyPair()
await server.listen(keyPair)server.refresh()
- Signature:
server.refresh() - Parameters: None.
- Returns: Nothing.
- Example:
server.refresh()Call this to reannounce the server address. HyperDHT also calls it automatically when the network changes.
server.address()
- Signature:
const address = server.address() - Parameters: None.
- Returns: An object with
host,port, andpublicKey. - Example:
const { host, port, publicKey } = server.address()
console.log(host, port, publicKey)server.on('connection', socket)
- Signature:
server.on('connection', socket => { ... }) - Parameters:
socket: ANoiseSecretStreamfor the accepted peer.
- Returns: Event subscription.
- Example:
server.on('connection', socket => {
console.log(socket.remotePublicKey)
})The socket exposes socket.remotePublicKey, and socket.handshakeHash is a shared identifier for the encrypted session.
server.on('listening')
- Signature:
server.on('listening', () => { ... }) - Parameters: A listener callback with no arguments.
- Returns: Event subscription.
- Example:
server.on('listening', () => {
console.log('ready')
})await server.close()
- Signature:
await server.close() - Parameters: None.
- Returns: A promise that resolves when the server has stopped listening.
- Example:
await server.close()server.on('close')
- Signature:
server.on('close', () => { ... }) - Parameters: A listener callback with no arguments.
- Returns: Event subscription.
- Example:
server.on('close', () => {
console.log('server closed')
})Clients and sockets
node.connect(remotePublicKey, [options])
- Signature:
const socket = node.connect(remotePublicKey, [options]) - Parameters:
remotePublicKey: The server public key as a buffer, hex string, or z-base32 string.options.nodes: Optional nearby DHT nodes that can speed up connection attempts.options.keyPair: Optional local key pair for the outgoing connection. Defaults tonode.defaultKeyPair.
- Returns: A
NoiseSecretStreamsocket. - Example:
const socket = node.connect(remotePublicKey)socket.on('open')
- Signature:
socket.on('open', () => { ... }) - Parameters: A listener callback with no arguments.
- Returns: Event subscription.
- Example:
socket.on('open', () => {
console.log('connected')
})socket.remotePublicKey
- Signature:
socket.remotePublicKey - Returns: The remote peer's public key buffer.
- Example:
console.log(socket.remotePublicKey)socket.publicKey
- Signature:
socket.publicKey - Returns: The local socket public key buffer.
- Example:
console.log(socket.publicKey)Peer discovery
node.lookup(topic, [options])
- Signature:
const stream = node.lookup(topic, [options]) - Parameters:
topic: A 32-byte topic buffer, typically a hash.options: Optional lookup settings forwarded todht-rpc.
- Returns: A stream of lookup responses shaped like
{ from, to, peers }. - Example:
for await (const result of node.lookup(topic)) {
console.log(result.peers)
}node.announce(topic, keyPair, [relayAddresses], [options])
- Signature:
const stream = node.announce(topic, keyPair, [relayAddresses], [options]) - Parameters:
topic: A 32-byte topic buffer.keyPair: The key pair being announced under that topic.relayAddresses: Optional array of up to three relay-capable nodes that help other peers connect faster.options: Optional announce settings forwarded todht-rpc.
- Returns: A stream with the same shape as
node.lookup(). - Example:
const stream = node.announce(topic, keyPair, server.nodes)
for await (const result of stream) {
console.log(result.from)
}Servers created with node.createServer() already announce themselves on the key pair they are listening on. Use node.announce() when you also want to publish a topic mapping.
await node.unannounce(topic, keyPair, [options])
- Signature:
await node.unannounce(topic, keyPair, [options]) - Parameters:
topic: The topic to stop announcing on.keyPair: The key pair previously announced for that topic.options: Optional unannounce settings forwarded todht-rpc.
- Returns: A promise that resolves when the announcement has been removed.
- Example:
await node.unannounce(topic, keyPair)Mutable and immutable records
await node.immutablePut(value, [options])
- Signature:
const { hash, closestNodes } = await node.immutablePut(value, [options]) - Parameters:
value: The immutable buffer or value to store in the DHT.options: Optional put settings forwarded todht-rpc.
- Returns: An object with the stored
hashandclosestNodes. - Example:
const { hash } = await node.immutablePut(Buffer.from('hello'))await node.immutableGet(hash, [options])
- Signature:
const { value, from } = await node.immutableGet(hash, [options]) - Parameters:
hash: The content hash returned byimmutablePut().options: Optional get settings forwarded todht-rpc.
- Returns: An object with the stored
valueand the responding node infrom. - Example:
const { value } = await node.immutableGet(hash)await node.mutablePut(keyPair, value, [options])
- Signature:
const { publicKey, closestNodes, seq, signature } = await node.mutablePut(keyPair, value, [options]) - Parameters:
keyPair: The signing key pair for the mutable record.value: The record value to publish.options: Optional put settings forwarded todht-rpc.
- Returns: An object with the announcing
publicKey,closestNodes,seq, andsignature. - Example:
const record = await node.mutablePut(keyPair, Buffer.from('v1'))await node.mutableGet(publicKey, [options])
- Signature:
const { value, from, seq, signature } = await node.mutableGet(publicKey, [options]) - Parameters:
publicKey: The public key for the mutable record.options.seq: Optional minimum sequence number to accept. Defaults to0.options.latest: Optional boolean that prefers the highest sequence number before returning. Defaults tofalse.- Any additional options are forwarded to
dht-rpc.
- Returns: An object with
value,from,seq, andsignature. - Example:
const { value, seq } = await node.mutableGet(keyPair.publicKey, {
latest: true
})Lifecycle
await node.destroy([options])
- Signature:
await node.destroy([options]) - Parameters:
options.force: Set totrueto force shutdown without waiting for servers to unannounce.
- Returns: A promise that resolves when the node is fully destroyed.
- Example:
await node.destroy()HyperDHT inherits additional lower-level RPC APIs from dht-rpc. Reach for those when you need custom queries beyond the keyed connection and record helpers above.
See also
- Connect two peers by key with HyperDHT — step-by-step direct peer connection flow.
- Connect to many peers by topic with Hyperswarm — higher-level topic discovery and connection management.
- Hyperswarm — higher-level swarm abstraction built on HyperDHT.
- Secretstream — the Noise-encrypted stream layer that wraps all HyperDHT connections.
- Hyperbeam — one-to-one encrypted pipe CLI built on HyperDHT.
- Hypershell — encrypted remote shell and file-copy tools built on HyperDHT.
- Hypertele — TCP proxy CLI built on HyperDHT.
- Hyperssh — SSH and SSHFS access routed through HyperDHT.