YuKumo

Node Deployment

Setup Lavalink v4 nodes for production with YuKumo.

Setup Lavalink v4 nodes for production with YuKumo.

docker run -d \
  --name lavalink \
  -p 2333:2333 \
  -v /path/to/application.yml:/opt/Lavalink/application.yml \
  ghcr.io/lavalink-devs/Lavalink:4

Manual

java -jar Lavalink.jar

application.yml

server:
  port: 2333
  address: 0.0.0.0

lavalink:
  server:
    password: "youshallnotpass"
    sources:
      youtube: true
      bandcamp: true
      soundcloud: true
      twitch: true
      vimeo: true
      http: true
      local: false
    filters:
      volume: true
      equalizer: true
      karaoke: true
      timescale: true
      tremolo: true
      vibrato: true
      rotation: true
      distortion: true
      channelMix: true
      lowPass: true

Node Configuration

const client = new YuKumo({
  nodes: [
    {
      host: "localhost",
      port: 2333,
      password: "youshallnotpass",
      name: "primary",
      secure: false,
      resumeTimeout: 60,
      resumeKey: "my-resume-key",
      maxRetries: 5,
      retryDelay: 1000,
      retryDelayMax: 30000,
    },
  ],
});

Multiple Nodes

new YuKumo({
  nodes: [
    { host: "eu.example.com", port: 2333, password: "pass1", name: "eu-west" },
    { host: "us.example.com", port: 2333, password: "pass2", name: "us-east" },
    { host: "asia.example.com", port: 2333, password: "pass3", name: "asia" },
  ],
});

YuKumo automatically distributes players across nodes.

Selection Strategies

StrategyBehavior
LeastUsedSelector(Default) Fewest players
LeastPenaltySelectorLowest penalty (players + CPU + frames)
CpuUsageSelectorLowest Lavalink CPU load
MemoryUsageSelectorLowest memory usage
LowestPingSelectorLowest WebSocket round-trip ping
RegionSelectorRegion-aware with fallback selector
RoundRobinSelectorRound-robin order
RandomSelectorRandom connected node
CustomSelectorCustom function `(nodes, guildId) => Node
client.nodes.setSelector(new RoundRobinSelector());

Custom selector

import type { NodeSelector, Node } from "yukumo";

class RegionAwareSelector implements NodeSelector {
  private regionMap = new Map<string, string>();

  constructor(regionMap: Record<string, string>) {
    for (const [guildId, region] of Object.entries(regionMap)) {
      this.regionMap.set(guildId, region);
    }
  }

  pick(nodes: Node[], guildId: string): Node | null {
    const preferred = this.regionMap.get(guildId);
    const connected = nodes.filter((n) => n.state === "connected");
    if (!connected.length) return null;

    if (preferred) {
      const regional = connected.filter((n) =>
        n.config.name?.startsWith(preferred),
      );
      if (regional.length) return regional[0];
    }

    return connected[0];
  }
}

Production Hardening

Connection resilience

{
  maxRetries: 10,
  retryDelay: 2000,
  retryDelayMax: 60000,
}

Session resumption

Avoid interruption during short restarts:

{
  resumeTimeout: 120,
  resumeKey: "your-unique-key",
}

JVM limits

java -Xmx2G -jar Lavalink.jar

Monitoring

client.on("nodeReady", (id) => console.log(`Ready: ${id}`));
client.on("nodeDisconnected", (id, code, reason) =>
  console.warn(`Disconnected: ${id} (${code}) ${reason}`),
);
client.on("nodeReconnected", (id) => console.log(`Reconnected: ${id}`));
client.on("nodeError", (id, error) => console.error(`Error on ${id}:`, error));
client.on("stats", (id, stats) => {
  console.log(`${id}: ${stats.playingPlayers} playing / ${stats.players} total`);
});

Troubleshooting

IssueSolution
Node won't connectCheck firewall, password, Lavalink logs
Frequent failoversIncrease maxRetries / retryDelay
High CPUAdd more nodes, reduce players per node
Session resume failsUse unique resumeKey per instance
401 UnauthorizedPassword mismatch with application.yml
403 ForbiddenCheck Lavalink IP whitelist / rate limits

On this page