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.
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.
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.
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.
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.
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 catchNodeManagerErrorif no node may be up. - Always check
node.readybefore forcing node-specific operations. - Use
node.restonly for low-level operations; prefer manager/player abstractions for typical flows. node.isNodelink()tells you the node is a fork, which skips plugin validation.