# HyperDHT



<Status level="stable" />

HyperDHT is the lower-level keyed connection layer underneath [Hyperswarm](/p2p/reference/building-blocks/hyperswarm). Use it when you want to dial a known public key directly or work with raw DHT discovery and record APIs.

## Install [#install]

```sh
npm i hyperdht
```

## Quickstart [#quickstart]

```js
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 [#api-reference]

### Node setup [#node-setup]

#### `new DHT([options])` [#new-dhtoptions]

[src](https://github.com/holepunchto/hyperdht/blob/v6.34.1/index.js#L26)

Create a new DHT node.

| Parameter | Type                                  | Default |
| --------- | ------------------------------------- | ------- |
| `options` | [`HyperDHTOptions`](#hyperdhtoptions) | `{}`    |

#### `keyPair = DHT.keyPair([seed])` [#keypair--dhtkeypairseed]

Use this method to generate the required keypair for DHT operations.

* Returns: an object with `{publicKey, secretKey}`.

#### `node = DHT.bootstrapper(port, host, [options])` [#node--dhtbootstrapperport-host-options]

If you want to run your own [Hyperswarm](/p2p/reference/building-blocks/hyperswarm) network use this method to easily create a bootstrap node.

#### `node.defaultKeyPair` [#nodedefaultkeypair]

[src](https://github.com/holepunchto/hyperdht/blob/v6.34.1/index.js#L35)

The default key pair for this node, derived from the `keyPair` or `seed` constructor option. Used by `node.connect()` and `server.listen()` when no key pair is passed explicitly.

### Servers [#servers]

#### `node.createServer([options], [onconnection])` [#nodecreateserveroptions-onconnection]

[src](https://github.com/holepunchto/hyperdht/blob/v6.34.1/index.js#L93)

Create a new server for accepting incoming encrypted P2P connections.

| Parameter      | Type                                                                       | Description                                      |
| -------------- | -------------------------------------------------------------------------- | ------------------------------------------------ |
| `options`      | [`CreateServerOptions`](#createserveroptions)                              | —                                                |
| `onconnection` | [`function(NoiseSecretStream): void`](/p2p/reference/helpers/secretstream) | Shorthand listener for the `'connection'` event. |

* Returns: `Server` — A server object — call `server.listen(keyPair)` to start accepting connections.

```js
{
  firewall (remotePublicKey, remoteHandshakePayload) {
    // validate if you want a connection from remotePublicKey
    // if you do return false, else return true
    // remoteHandshakePayload contains their ip and some more info
    return true
  }
}
```

#### `await server.listen(keyPair)` [#await-serverlistenkeypair]

Make the server listen on a keyPair. To connect to this server use keyPair.publicKey as the connect address.

* Throws:
  * `ALREADY_LISTENING` if the server is already listening.
  * `NODE_DESTROYED` if the DHT node has been destroyed.

#### `server.refresh()` [#serverrefresh]

Refresh the server, causing it to reannounce its address. This is automatically called on network changes.

Call this to reannounce the server address. HyperDHT also calls it automatically when the network changes.

#### `server.address()` [#serveraddress]

You can also get this info from `node.remoteAddress()` minus the public key.

* Returns: an object containing the address of the server:

```js
{
  ;(host, // external IP of the server,
    port, // external port of the server if predictable,
    publicKey) // public key of the server
}
```

#### `server.on('connection', socket)` [#serveronconnection-socket]

Emitted when a new encrypted connection has passed the firewall check.

The socket exposes `socket.remotePublicKey`, and `socket.handshakeHash` is a shared identifier for the encrypted session.

#### `server.on('listening')` [#serveronlistening]

Emitted when the server is fully listening on a keyPair.

#### `await server.close()` [#await-serverclose]

Stop listening.

#### `server.on('close')` [#serveronclose]

Emitted when the server is fully closed.

### Clients and sockets [#clients-and-sockets]

#### `node.connect(remotePublicKey, [options])` [#nodeconnectremotepublickey-options]

[src](https://github.com/holepunchto/hyperdht/blob/v6.34.1/index.js#L89)

Connect to a remote server. Similar to `createServer` this performs UDP holepunching for P2P connectivity.

| Parameter         | Type                                                                | Description                                                                      |
| ----------------- | ------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| `remotePublicKey` | [`Buffer\|string`](https://nodejs.org/api/buffer.html#class-buffer) | Public key of the server to connect to (Buffer, hex string, or z-base32 string). |
| `options`         | [`ConnectOptions`](#connectoptions)                                 | —                                                                                |

* Returns: [`NoiseSecretStream`](/p2p/reference/helpers/secretstream) — An encrypted duplex stream — use `socket.on('open', ...)` to know when it is ready.

#### `socket.on('open')` [#socketonopen]

Emitted when the encrypted connection has been fully established with the server.

#### `socket.remotePublicKey` [#socketremotepublickey]

The public key of the remote peer.

#### `socket.publicKey` [#socketpublickey]

The public key of the local socket.

### Peer discovery [#peer-discovery]

#### `node.lookup(topic, [options])` [#nodelookuptopic-options]

[src](https://github.com/holepunchto/hyperdht/blob/v6.34.1/index.js#L202)

Look for peers in the DHT on the given topic. Topic should be a 32 byte buffer (normally a hash of something).

| Parameter | Type                                                        | Default | Description                     |
| --------- | ----------------------------------------------------------- | ------- | ------------------------------- |
| `topic`   | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | —       | —                               |
| `options` | `object`                                                    | `{}`    | Options forwarded to `dht-rpc`. |

* Returns: `QueryStream` — An async-iterable query stream whose values are `{ from, to, peers }` objects.

#### `node.findPeer(publicKey, [options])` [#nodefindpeerpublickey-options]

[src](https://github.com/holepunchto/hyperdht/blob/v6.34.1/index.js#L196)

Find the addresses of a specific peer, keyed by `hash(publicKey)`—a `lookup` specialized for locating one peer rather than a topic. Pass `{ hash: false }` in `options` to query the raw `publicKey` as the topic instead of its hash.

| Parameter   | Type                                                        | Default | Description                                                                       |
| ----------- | ----------------------------------------------------------- | ------- | --------------------------------------------------------------------------------- |
| `publicKey` | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | —       | The 32-byte public key of the peer to locate.                                     |
| `options`   | `object`                                                    | `{}`    | Forwarded to the underlying query; set `hash: false` to skip hashing `publicKey`. |

* Returns: `QueryStream` — An async-iterable query stream, like `node.lookup()`.

#### `node.announce(topic, keyPair, [relayAddresses], [options])` [#nodeannouncetopic-keypair-relayaddresses-options]

[src](https://github.com/holepunchto/hyperdht/blob/v6.34.1/index.js#L254)

Announce that you are listening on a key-pair to the DHT under a specific topic.

| Parameter        | Type                                                                                                                            | Default | Description                                                      |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------- | ---------------------------------------------------------------- |
| `topic`          | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer)                                                                     | —       | 32-byte topic buffer to announce under.                          |
| `keyPair`        | [`{publicKey: Buffer, secretKey: Buffer}`](https://nodejs.org/api/buffer.html#class-buffer)                                     | —       | The Ed25519 key pair to announce with.                           |
| `relayAddresses` | [`Array<{host: string, port: number}>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) | —       | Up to 3 DHT relay node addresses to include in the announcement. |
| `options`        | `object`                                                                                                                        | `{}`    | Options forwarded to `dht-rpc`.                                  |

* Returns: `QueryStream` — An async-iterable query stream (same shape as `lookup()`).

```js
const topic = DHT.hash(Buffer.from('my-topic'))
const stream = node.announce(topic, keyPair)
await stream.finished()
```

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])` [#await-nodeunannouncetopic-keypair-options]

[src](https://github.com/holepunchto/hyperdht/blob/v6.34.1/index.js#L250)

Unannounce a key-pair.

| Parameter | Type                                                                                        | Default | Description                                           |
| --------- | ------------------------------------------------------------------------------------------- | ------- | ----------------------------------------------------- |
| `topic`   | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer)                                 | —       | 32-byte topic buffer previously used in `announce()`. |
| `keyPair` | [`{publicKey: Buffer, secretKey: Buffer}`](https://nodejs.org/api/buffer.html#class-buffer) | —       | The Ed25519 key pair to unannounce.                   |
| `options` | `object`                                                                                    | `{}`    | Options forwarded to `dht-rpc`.                       |

* Returns: [`Promise<void>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — Resolves when the unannounce query has completed.

```js
const topic = DHT.hash(Buffer.from('my-topic'))
await node.unannounce(topic, keyPair)
```

### Mutable and immutable records [#mutable-and-immutable-records]

#### `await node.immutablePut(value, [options])` [#await-nodeimmutableputvalue-options]

[src](https://github.com/holepunchto/hyperdht/blob/v6.34.1/index.js#L291)

Store an immutable value in the DHT. When successful, the hash of the value is returned.

| Parameter | Type                                                        | Default | Description                     |
| --------- | ----------------------------------------------------------- | ------- | ------------------------------- |
| `value`   | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | —       | The value to store (a Buffer).  |
| `options` | `object`                                                    | `{}`    | Options forwarded to `dht-rpc`. |

* Returns: [`Promise<{hash: Buffer, closestNodes: Array<object>}>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — Object with the 32-byte `hash` and the `closestNodes` that stored the value.

```js
const { hash } = await node.immutablePut(Buffer.from('hello world'))
const result = await node.immutableGet(hash)
console.log(result.value.toString()) // 'hello world'
```

#### `await node.immutableGet(hash, [options])` [#await-nodeimmutablegethash-options]

[src](https://github.com/holepunchto/hyperdht/blob/v6.34.1/index.js#L276)

Fetch an immutable value from the DHT. When successful, it returns the value corresponding to the hash.

| Parameter | Type                                                        | Default | Description                                                        |
| --------- | ----------------------------------------------------------- | ------- | ------------------------------------------------------------------ |
| `hash`    | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | —       | 32-byte hash of the value to fetch (returned by `immutablePut()`). |
| `options` | `object`                                                    | `{}`    | Options forwarded to `dht-rpc`.                                    |

* Returns: [`Promise<{token: Buffer, from: object, to: object, value: Buffer}\|null>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — The result node or `null` if not found.

```js
const result = await node.immutableGet(hash)
if (result) console.log(result.value.toString())
```

#### `await node.mutablePut(keyPair, value, [options])` [#await-nodemutableputkeypair-value-options]

[src](https://github.com/holepunchto/hyperdht/blob/v6.34.1/index.js#L365)

Store a mutable value in the DHT.

| Parameter | Type                                                                                        | Default | Description                              |
| --------- | ------------------------------------------------------------------------------------------- | ------- | ---------------------------------------- |
| `keyPair` | [`{publicKey: Buffer, secretKey: Buffer}`](https://nodejs.org/api/buffer.html#class-buffer) | —       | Ed25519 key pair used to sign the value. |
| `value`   | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer)                                 | —       | The value to store (a Buffer).           |
| `options` | [`MutablePutOptions`](#mutableputoptions)                                                   | `{}`    | Put options.                             |

* Returns: [`Promise<{publicKey: Buffer, closestNodes: Array<object>, seq: number, signature: Buffer}>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — The stored record metadata.

```js
const keyPair = DHT.keyPair()
const { seq } = await node.mutablePut(keyPair, Buffer.from('v1'), { seq: 0 })
console.log('stored at seq', seq)
```

#### `await node.mutableGet(publicKey, [options])` [#await-nodemutablegetpublickey-options]

[src](https://github.com/holepunchto/hyperdht/blob/v6.34.1/index.js#L312)

Fetch a mutable value from the DHT.

| Parameter   | Type                                                        | Default | Description                                                                    |
| ----------- | ----------------------------------------------------------- | ------- | ------------------------------------------------------------------------------ |
| `publicKey` | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | —       | Ed25519 public key of the key pair used to sign the value with `mutablePut()`. |
| `options`   | [`MutableGetOptions`](#mutablegetoptions)                   | `{}`    | Fetch options.                                                                 |

* Returns: [`Promise<{token: Buffer, from: object, to: object, seq: number, value: Buffer, signature: Buffer}\|null>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — The latest matching result, or `null` if not found.

```js
const result = await node.mutableGet(keyPair.publicKey)
if (result) console.log(result.value.toString(), 'seq:', result.seq)
```

### Lifecycle [#lifecycle]

#### `await node.suspend([options])` [#await-nodesuspendoptions]

[src](https://github.com/holepunchto/hyperdht/blob/v6.34.1/index.js#L115)

Suspend the node's network activity—used when the host device is about to sleep or lose connectivity. Suspends every listening server, clears raw streams, and suspends the underlying `dht-rpc` instance; new connections are refused while suspended.

| Parameter | Type     | Default | Description                                                  |
| --------- | -------- | ------- | ------------------------------------------------------------ |
| `options` | `object` | `{}`    | Pass `{ log }` with a function to receive progress messages. |

* Returns: [`Promise<void>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — Resolves once the node is fully suspended.

#### `await node.resume([options])` [#await-noderesumeoptions]

[src](https://github.com/holepunchto/hyperdht/blob/v6.34.1/index.js#L105)

Resume a suspended node: resumes `dht-rpc` and re-resumes every listening server. Call this after the device wakes or regains connectivity.

| Parameter | Type     | Default | Description                                                  |
| --------- | -------- | ------- | ------------------------------------------------------------ |
| `options` | `object` | `{}`    | Pass `{ log }` with a function to receive progress messages. |

* Returns: [`Promise<void>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — Resolves once the node is fully resumed.

#### `await node.destroy([options])` [#await-nodedestroyoptions]

[src](https://github.com/holepunchto/hyperdht/blob/v6.34.1/index.js#L131)

Fully destroy this DHT node.

| Parameter | Type     | Default | Description                                                                      |
| --------- | -------- | ------- | -------------------------------------------------------------------------------- |
| `options` | `object` | `{}`    | Pass `{ force: true }` to skip waiting for servers to unannounce before closing. |

* Returns: [`Promise<void>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — Resolves when the node is fully shut down.

```js
await node.destroy()
// or, to skip graceful unannounce:
await node.destroy({ force: true })
```

#### `node.stats` [#nodestats]

[src](https://github.com/holepunchto/hyperdht/blob/v6.34.1/index.js#L59)

Observability counters, including `punches.tryLater` and `punches.tryLaterRelayedHandshakesAtLeastOnce` (rate-limited hole-punch attempts) and `socketPool.socketsAdded`/`socketPool.socketsRemoved` (socket pool lifecycle).

* Returns: `object`

HyperDHT inherits additional lower-level RPC APIs from [`dht-rpc`](https://github.com/mafintosh/dht-rpc). Reach for those when you need custom queries beyond the keyed connection and record helpers above.

## Types [#types]

### HyperDHTOptions [#hyperdhtoptions]

Options for creating a HyperDHT node.

| Property              | Type                                                                                                      | Default | Description                                                                                   |
| --------------------- | --------------------------------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------- |
| `bootstrap`           | [`Array<string>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) | —       | Bootstrap server addresses (`'host:port'`). Defaults to the Holepunch public bootstrap nodes. |
| `keyPair`             | [`{publicKey: Buffer, secretKey: Buffer}`](https://nodejs.org/api/buffer.html#class-buffer)               | —       | Default key pair used for `server.listen()` and `connect()`.                                  |
| `connectionKeepAlive` | `number\|false`                                                                                           | `5000`  | Keep-alive interval in ms for all opened sockets. Set `false` to disable.                     |
| `randomPunchInterval` | `number`                                                                                                  | `20000` | Minimum ms between random holepunches.                                                        |

### CreateServerOptions [#createserveroptions]

Options for `node.createServer()`.

| Property            | Type                                                                                                                                        | Default | Description                                                                                                                                                                                                                                                               |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `firewall`          | [`function(Buffer, object): boolean`](https://nodejs.org/api/buffer.html#class-buffer)                                                      | —       | Called with `(remotePublicKey, remoteHandshakePayload)`. Return `true` to block, `false` to allow.                                                                                                                                                                        |
| `holepunch`         | [`function(number, number, Array, Array): boolean`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) | —       | Called before holepunching begins. Return `false` to abort.                                                                                                                                                                                                               |
| `relayThrough`      | [`Buffer\|Array<Buffer>\|function(): Buffer\|null`](https://nodejs.org/api/buffer.html#class-buffer)                                        | —       | Optionally relay through a specific peer — pass a public key (Buffer), an array of public keys to pick from, or a function returning one.                                                                                                                                 |
| `relayKeepAlive`    | `number`                                                                                                                                    | `5000`  | Keep-alive interval in ms for the relay socket.                                                                                                                                                                                                                           |
| `relayRecoveryWait` | `number`                                                                                                                                    | `30000` | How long in ms the server waits, after it loses the relay a client was paired through, for a direct connection to take over. Once the wait is over, and no hole punch is still running, the server releases the unconnected stream and its hole puncher. Added in 6.34.1. |

### ConnectOptions [#connectoptions]

Options for `node.connect()`.

| Property         | Type                                                                                                                            | Default | Description                                                                                                                               |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `nodes`          | [`Array<{host: string, port: number}>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) | —       | Known DHT nodes close to the remote — speeds up connecting.                                                                               |
| `relayAddresses` | [`Array<{host: string, port: number}>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) | —       | Relay server addresses to hole-punch through when a direct connection cannot be established.                                              |
| `keyPair`        | [`{publicKey: Buffer, secretKey: Buffer}`](https://nodejs.org/api/buffer.html#class-buffer)                                     | —       | Key pair to use for this connection. Defaults to `node.defaultKeyPair`.                                                                   |
| `relayThrough`   | [`Buffer\|Array<Buffer>\|function(): Buffer\|null`](https://nodejs.org/api/buffer.html#class-buffer)                            | —       | Optionally relay through a specific peer — pass a public key (Buffer), an array of public keys to pick from, or a function returning one. |

### MutableGetOptions [#mutablegetoptions]

Options for `node.mutableGet()`.

| Property  | Type                        | Default | Description                                                                     |
| --------- | --------------------------- | ------- | ------------------------------------------------------------------------------- |
| `seq`     | `number`                    | `0`     | Only return values whose `seq` is >= this number.                               |
| `latest`  | `boolean`                   | `true`  | If `true`, scan the whole query and return the highest `seq` seen.              |
| `refresh` | `function(object): boolean` | —       | Called with the latest result; return `true` to re-store it, extending its TTL. |

### MutablePutOptions [#mutableputoptions]

Options for `node.mutablePut()`.

| Property      | Type                                                                                                   | Default | Description                                                                                 |
| ------------- | ------------------------------------------------------------------------------------------------------ | ------- | ------------------------------------------------------------------------------------------- |
| `seq`         | `number`                                                                                               | `0`     | Sequence number for this value. Must be greater than the current stored `seq` to overwrite. |
| `signMutable` | [`function(number, Buffer, object): Promise<Buffer>`](https://nodejs.org/api/buffer.html#class-buffer) | —       | Custom signing function. Defaults to the built-in Ed25519 signer.                           |

## Errors [#errors]

Coded errors this module can throw — catch them via `err.code`.

| Error               | Thrown when                         |
| ------------------- | ----------------------------------- |
| `ALREADY_LISTENING` | if the server is already listening. |
| `NODE_DESTROYED`    | if the DHT node has been destroyed. |

## See also [#see-also]

* [Connect two peers by key with HyperDHT](/p2p/how-to/connect-to-peers/connect-two-peers-by-key-with-hyperdht)—step-by-step direct peer connection flow.
* [Connect to many peers by topic with Hyperswarm](/p2p/how-to/connect-to-peers/connect-to-many-peers-by-topic-with-hyperswarm)—higher-level topic discovery and connection management.
* [Hyperswarm](/p2p/reference/building-blocks/hyperswarm)—higher-level swarm abstraction built on HyperDHT.
* [Secretstream](/p2p/reference/helpers/secretstream)—the Noise-encrypted stream layer that wraps all HyperDHT connections.
* [Hyperbeam](/p2p/reference/tools/hyperbeam)—one-to-one encrypted pipe CLI built on HyperDHT.
* [Hypershell](/p2p/reference/tools/hypershell)—encrypted remote shell and file-copy tools built on HyperDHT.
* [Hypertele](/p2p/reference/tools/hypertele)—TCP proxy CLI built on HyperDHT.
* [Hyperssh](/p2p/reference/tools/hyperssh)—SSH and SSHFS access routed through HyperDHT.
