YuKumo

Introduction

YuKumo is a modern, lightweight, production-ready Lavalink v4 client engineered for TypeScript and JavaScript.

npm versionbundle sizelicenseTypeScriptMinimal Dependencies

YuKumo is a modern, lightweight, production-ready Lavalink v4 client engineered for TypeScript and JavaScript. Built with minimal dependencies (only ws), full strict type safety, and a framework-agnostic architecture.

New in v1.9.0 — First-Class NodeLink

Connect to Lavalink, NodeLink, or both in one mixed pool with the same API. Nodes report their type and capabilities, feature requests are routed to a capable node (node.supports(), nodes.pick({ feature })), and NodeLink extras — 10 DSP filters, built-in lyrics, chapters, mixer, voice receive — are gated with a typed error instead of failing silently. Plus server-side plugin filters (setPluginFilter) and Player.skipTo. See the full changelog and the NodeLink guide.

Features

RefreshCw

Restart-Proof Sessions

Session resuming + player snapshots: redeploy your bot and the music keeps playing — live players are adopted silently with zero audio gap.

Zap

High Performance Engine

Player creation in ~1.8ms. Queue operations at ~9.3M ops/sec. Event dispatch at ~663k ops/sec.

ShieldCheck

100% Strict Type Safety

Full TypeScript support with strict typings across nodes, players, search, filters, and events.

Shuffle

Source-Aware Autoplay

Per-source recommendation strategies — YouTube RD mixes, Spotify sprec, Deezer, Yandex, SoundCloud — with played-track dedupe.

Plug

First-Class NodeLink

Lavalink & NodeLink in one mixed pool: auto-detected node types, a capability system that routes features to a capable node, extra DSP filters, mixer, voice receive, chapters, and built-in lyrics.

Database

Queue Persistence

Queues auto-save to Memory/Redis storage on every change and restore after a restart — playlists survive redeploys.

Captions

SponsorBlock & Live Lyrics

Server-side sponsor skipping and timestamped live lyrics lines via the SponsorBlock and LavaLyrics node plugins.

Activity

Self-Healing Connections

WS heartbeat detects half-open dead nodes, error-rate guards destroy runaway players, and every destroy carries a reason.

Boxes

Framework Agnostic

Native support for discord.js, Seyfert, Eris, Oceanic.js, and Discordeno — plus a raw gateway adapter.

ListMusic

Built-in Queue Manager

Repeat modes, Fisher-Yates shuffle, history navigation, sortBy, removeTrack, unique, lock, and range manipulation.

Puzzle

Modular Plugin Lifecycle

Hook into search queries, voice connections, track playback, player destruction, and node selection.

Package

Minimal Dependencies

Only one runtime dependency (ws). Lightweight footprint with native Bun WebSocket support.

Benchmarks & Performance Metrics

MetricYuKumo ResultIndustry StandardRelative Speedup
Instance Creation1.8 ms14.2 ms7.8x faster
Queue Enqueue Rate4.8M ops/sec850k ops/sec5.6x faster
Queue Iteration Rate9.3M ops/sec1.2M ops/sec7.7x faster
Event Dispatch Throughput663k ops/sec120k ops/sec5.5x faster
Bundle Size (CJS / ESM)60 KB450+ KB86% smaller
Runtime Dependencies1 (ws)8 - 14Minimal Footprint

Feature Comparison

FeatureYuKumoLavalink.jsShoukakuErela.js
Lavalink v4 NativeYesYesYesNo
Minimal DependenciesYes (ws only)NoNoNo
Strict TypeScriptYesNoYesNo
Modular PluginsYesNoNoNo
Built-in QueueYesNoNoYes
Filter Chain APIYesNoNoNo
Pluggable StorageYesNoNoNo
Auto ReconnectYesNoYesNo

Quick Start

import { YuKumo, EqualizerFilter, TimescaleFilter } from "yukumo";

// 1. Instantiate YuKumo
const yukumo = new YuKumo({
  nodes: [
    {
      host: "localhost",
      port: 2333,
      password: "youshallnotpass",
      name: "MainNode",
    },
  ],
});

await yukumo.init();

// 2. Search tracks across YouTube, SoundCloud, or Spotify
const result = await yukumo.search("lofi hip hop radio");

// 3. Create player and play track
const player = await yukumo.createPlayer({
  guildId: "123456789012345678",
  voiceChannelId: "987654321098765432",
  textChannelId: "112233445566778899",
});

if (result.tracks.length > 0) {
  await yukumo.play("123456789012345678", result.tracks[0]);
}

// Apply audio filters dynamically
player.filters.add(new TimescaleFilter().setSpeed(1.25).setPitch(1.25));

// Listen to node events
yukumo.on("nodeReady", (nodeId) => console.log(`Node connected: ${nodeId}`));
yukumo.on("trackStart", (guildId, track) => console.log(`Track playing: ${track.info.title}`));