Quickstart
Wire Lunacord core with discord.js — Lavalink manager, gateway voice packets, and playback.
1. Install
bun add @lunacord/core discord.jsOptional: @lunacord/lyrics, @lunacord/cache-redis, @lunacord/plugins match what you need.
2. Start a Lavalink v4 server
Download the latest Lavalink v4 jar and run:
java -jar Lavalink.jarDefault port is 2333, default password is youshallnotpass.
3. Create Lunacord and attach Discord
You forward gateway events, send op: 4 voice payloads through the shard, and bind identity after the client is ready:
import { Lunacord } from "@lunacord/core";
import { Client, GatewayIntentBits } from "discord.js";
const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates],
});
const lunacord = Lunacord.create()
.nodes([{ id: "main", host: "localhost", port: 2333, password: "youshallnotpass" }])
.autoConnect(false)
.resume(true)
.sendGatewayPayload((guildId, payload) => {
client.guilds.cache.get(guildId)?.shard.send(payload);
})
.build();
client.on("raw", (packet) => {
lunacord.handleVoicePacket(packet);
});
client.once("clientReady", async () => {
const user = client.user;
if (!user) return;
const numShards =
client.shard?.count ?? (client.ws.shards ? client.ws.shards.size : undefined) ?? 1;
lunacord.bindIdentity({ userId: user.id, numShards });
await lunacord.connect();
});
await client.login(process.env.DISCORD_TOKEN);4. Join voice and play
Use your own command handler. The usual flow is: resolve the invoker’s voice channel id, then create or reuse a player, connect to that channel, then load tracks:
const player = await lunacord
.createPlayer()
.setGuild(guildId)
.setVoiceChannel(voiceChannelId)
.setTextChannel(textChannelId)
.connect();
const result = await player.searchAndPlay(query, "ytsearch");See Lunacord and Player for the full API.
5. Batteries-included shortcut
For automatic raw forwarding, bindIdentity, default slash commands, and embeds, use MusicKit and the MusicKit Quickstart instead.