Rayav1.0.0
New: voice channel status

Music that
never stops.

Raya is the Lavalink v4 client for Node.js that survives bot restarts, dead nodes and network blips, and still fits in a few lines of code.

npm install raya.js
bot.jsconnected
import { Raya, Connectors } from 'raya.js';

const raya = new Raya({
  nodes: [{ host: 'localhost', password: 'youshallnotpass' }],
  connector: new Connectors.DiscordJS(client),
  playerDefaults: { autoplay: true },
  voiceStatus: true,
});

const player = await raya.join({ guildId, voiceChannelId });
await player.enqueue(await player.search('neon tide'));
1runtime dependencyjust ws
63automated testsagainst a Lavalink v4 simulator
12search sourcesYouTube to Qobuz
4β†’1calls, one requestsame-tick batching
Live demo

Play with a Raya player

A simulated player that follows Raya's real queue rules. Each click shows the method you'd call, the request Raya sends, and the events your bot receives.

β™ͺ
Idle

Nothing playing

Add a track from the search box

0:0020Γ— demo speed0:00
    Up next0 tracks
      What your bot sees
      your callrequest to LavalinkeventAll events β†’
      Resilience simulator

      Break things. The music keeps going.

      Each dot is a guild's player. Crash a Lavalink node, cut its network, or restart your bot, and watch what Raya does, with the same events your code gets.

      How it works β†’
      Events
      Fast by default

      Four calls. One request.

      Most clients send a request per method call. Raya collects what you change in the same tick and sends it together, in order, so bots with hundreds of guilds stay light on their Lavalink nodes.

      • Same-tick batchingChanges made together go out as one PATCH, still in order.
      • Local track decodingdecodeTrack() reads the binary track format without calling Lavalink.
      • Search cache and de-dupeRepeated or simultaneous searches reuse one request.
      • No per-player pollingPosition is calculated when you read it, with no timer per guild.
      See batching in the filters guide β†’
      player.setVolume(80)player.pause()player.filters.nightcore()player.filters.bassBoost('low')
      same tick
      PATCH /v4/sessions/:id/players/:guild
      {
        "volume": 80,
        "paused": true,
        "filters": { "timescale": {…}, "equalizer": [ … ] }
      }
      0method calls
      0HTTP requests
      Easy to start

      Up and running in a few lines

      Pick your Discord library. The connector handles raw gateway events, voice updates and startup for you.

      const { Client, GatewayIntentBits } = require('discord.js');
      const { Raya, Connectors } = require('raya.js');
      
      const client = new Client({
        intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates],
      });
      
      const raya = new Raya({
        nodes: [{ name: 'main', host: 'localhost', password: 'youshallnotpass' }],
        connector: new Connectors.DiscordJS(client),
      });
      
      raya.on('trackStart', (player, track) => {
        client.channels.cache.get(player.textChannelId)?.send(`Now playing **${track.info.title}**`);
      });
      
      client.login(process.env.DISCORD_TOKEN);
      Want your exact setup?Open the Config Builder β†’
      From LavaFlow

      Rebuilt, not just renamed

      Raya started from LavaFlow's code and fixed what held it back.

      LavaFlow:setVolume(100) sent 1000, ten times too loud
      Raya:Volume 0-1000, where 100 is unchanged
      LavaFlow:Idle nodes dropped after about 60 seconds
      Raya:WebSocket pings keep idle nodes connected
      LavaFlow:v3 Resume-Key header, so resuming never worked
      Raya:Real v4 Session-Id resuming
      LavaFlow:play() could run before the node had a session
      Raya:Players only use nodes with a ready session
      LavaFlow:Health check deleted nodes that were reconnecting
      Raya:Backoff reconnects plus automatic failover
      LavaFlow:A global NodeManager shared nodes between managers
      Raya:Each Raya instance owns its nodes

      Read the migration guide β†’

      Ready when your bot is.

      Install Raya, connect a node, and let it handle the hard parts.

      npm install raya.js