Guides

Node Management

Select nodes, check health, and perform low-level node operations.

This guide covers node selection strategies, health checks, and operations like decode and REST calls.

Select Nodes

getLeastUsed() picks among the connected nodes and throws a NodeManagerError when there are none — it never returns undefined.

node-selection.ts
import {  } from 'hoshimi';
import type {  } from 'hoshimi';

declare const : ;

const  = ..(); // default
const  = ..(.);
const  = ..(() => .?. ?? 0);

.(`Using node: ${.}`);
.(`Ready: ${.}`);
.(`Penalties: ${.}`);
.(., .);

Sort strategies: Penalties (default), Players, PlayingPlayers, Cpu, SystemLoad, LavalinkLoad, Memory — or any function returning a number, where lowest wins. Penalties combine the player count with CPU load and frame deficits.

Moving players between nodes

player.move() re-creates the player on another node, keeping position, volume and filters. It refuses the move when the target lacks a source manager the queue depends on, so a Spotify queue never lands on a node that cannot play it.

node-move.ts
import type { ,  } from 'hoshimi';

declare const : ;
declare const : ;

await .(..());

Set nodeOptions.moveOptions.move to have Hoshimi do this automatically for every player of a node that disconnects, picking the target with moveOptions.filterBy.

Decode Tracks

Decode Lavalink track data to extract metadata.

track-decoding.ts
import type {  } from 'hoshimi';

declare const : ;

const  = await ..('QAAAyAIA...', 'user-id');
const  = await ..(['QAAAyAIA...', 'QAAByAIA...'], 'user-id');

.(..);
.(.);

REST Operations

Access low-level REST endpoints for advanced use cases.

rest-operations.ts
import type {  } from 'hoshimi';

declare const : ;

const  = await ..();
.(`Active players: ${.}`);

Staying connected

Each socket runs a ping/pong heartbeat: if a ping goes unanswered within nodeOptions.heartbeatOptions.interval (30s by default), the socket is terminated and the normal reconnect path takes over. Set it to 0 to disable.

A dropped node retries retryAmount times, retryDelay apart, then destroys itself and emits NodeError. With sessionOptions.resumable the node keeps its Lavalink session alive for timeout seconds, so players survive a restart; with byLibrary, Hoshimi replays its own state onto the node instead of relying on Lavalink's resume.

Customizing the library resume

When byLibrary is on, Hoshimi runs a built-in handler on a fresh connect that reconnects each player it still holds — destroying the empty ones, resending the voice state, syncing the queue and replaying the current track. Override it with sessionOptions.resumeFn to supply your own logic, without patching the library or wiring an event. The built-in resumeByLibrary is exported, so you can wrap it instead of replacing it wholesale.

custom-resume.ts
const  = ({
  ,
  : [{ : 'localhost', : 2333, : 'youshallnotpass' }],
  : {
    : {
      : true,
      async (, ) {
        // Your own reconnect logic, then hand off to the built-in one.
        await (, );
      },
    },
  },
});

resumeFn runs only while byLibrary is enabled, and defaults to resumeByLibrary when omitted — so leaving it out keeps the built-in behavior.

Best Practices

  • Prefer getLeastUsed() for default load balancing, and catch NodeManagerError if no node may be up.
  • Always check node.ready before forcing node-specific operations.
  • Use node.rest only for low-level operations; prefer manager/player abstractions for typical flows.
  • node.isNodelink() tells you the node is a fork, which skips plugin validation.