Skip to main content

Quick Start Guide

This guide will help you build a basic but fully functional music bot using Discord Player. By the end, you’ll have a bot that can play music from various sources!

Prerequisites

Before you begin, make sure you have:

Step 1: Initialize Your Bot

Create a new file called index.js and set up your Discord client:
index.js
const { Client, GatewayIntentBits } = require('discord.js');
const { Player } = require('discord-player');
const { DefaultExtractors } = require('@discord-player/extractor');

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.GuildVoiceStates,
    GatewayIntentBits.MessageContent,
  ],
});
The GuildVoiceStates intent is required for Discord Player to work. Without it, the bot won’t be able to connect to voice channels.

Step 2: Create the Player Instance

Create the main player instance and load extractors:
index.js
// Create the player instance - this is the entrypoint for discord-player
const player = new Player(client);

// Load all default extractors
player.extractors.loadMulti(DefaultExtractors).then(() => {
  console.log('Extractors loaded successfully');
});
The Player instance handles and keeps track of all queues and their components. You only need one player instance for your entire bot.

Step 3: Set Up Event Listeners

Discord Player is event-based. Let’s add listeners for important events:
index.js
// Emitted when a track starts playing
player.events.on('playerStart', (queue, track) => {
  queue.metadata.channel.send(`Now playing **${track.cleanTitle}**!`);
});

// Emitted when an error occurs
player.events.on('error', (queue, error) => {
  console.error(`Error in ${queue.guild.name}: ${error.message}`);
});

// Emitted when a track is added to the queue
player.events.on('audioTrackAdd', (queue, track) => {
  queue.metadata.channel.send(`Added **${track.cleanTitle}** to the queue!`);
});

// Emitted when the queue is empty
player.events.on('emptyQueue', (queue) => {
  queue.metadata.channel.send('Queue finished!');
});
The queue.metadata object is where you store custom data like the text channel reference. You’ll set this when creating the queue.

Step 4: Create the Play Command

Now let’s create a simple play command using Discord.js interaction commands:
play.js
const { SlashCommandBuilder } = require('discord.js');
const { useMainPlayer } = require('discord-player');

module.exports = {
  data: new SlashCommandBuilder()
    .setName('play')
    .setDescription('Play a song')
    .addStringOption(option =>
      option
        .setName('query')
        .setDescription('The song you want to play')
        .setRequired(true)
    ),

  async execute(interaction) {
    const player = useMainPlayer();
    const channel = interaction.member.voice.channel;
    
    if (!channel) {
      return interaction.reply('You need to be in a voice channel!');
    }

    const query = interaction.options.getString('query', true);

    // Defer the reply as searching and loading can take time
    await interaction.deferReply();

    try {
      const { track } = await player.play(channel, query, {
        nodeOptions: {
          metadata: {
            channel: interaction.channel,
            client: interaction.guild.members.me,
            requestedBy: interaction.user,
          },
        },
      });

      return interaction.followUp(`**${track.cleanTitle}** enqueued!`);
    } catch (error) {
      return interaction.followUp(`Something went wrong: ${error.message}`);
    }
  },
};
The useMainPlayer() hook allows you to access the player instance from anywhere in your code without passing it around.

Step 5: Add Queue Control Commands

Let’s add more commands to control the queue:
const { SlashCommandBuilder } = require('discord.js');
const { useQueue } = require('discord-player');

module.exports = {
  data: new SlashCommandBuilder()
    .setName('skip')
    .setDescription('Skip the current song'),

  async execute(interaction) {
    const queue = useQueue(interaction.guild.id);

    if (!queue || !queue.isPlaying()) {
      return interaction.reply('No music is currently playing!');
    }

    queue.node.skip();
    return interaction.reply('Skipped the current song!');
  },
};

Step 6: Register Commands and Start the Bot

Finally, let’s register the commands and start the bot:
index.js
const fs = require('fs');
const path = require('path');

// Load commands
client.commands = new Map();
const commandsPath = path.join(__dirname, 'commands');
const commandFiles = fs
  .readdirSync(commandsPath)
  .filter(file => file.endsWith('.js'));

for (const file of commandFiles) {
  const command = require(path.join(commandsPath, file));
  client.commands.set(command.data.name, command);
}

// Handle interactions
client.on('interactionCreate', async interaction => {
  if (!interaction.isChatInputCommand()) return;

  const command = client.commands.get(interaction.commandName);
  if (!command) return;

  try {
    await player.context.provide({ guild: interaction.guild }, () =>
      command.execute(interaction)
    );
  } catch (error) {
    console.error(error);
    const reply = {
      content: 'There was an error executing that command!',
      ephemeral: true,
    };
    
    if (interaction.replied || interaction.deferred) {
      await interaction.followUp(reply);
    } else {
      await interaction.reply(reply);
    }
  }
});

// Ready event
client.once('ready', () => {
  console.log(`Logged in as ${client.user.tag}`);
});

// Login
client.login('YOUR_BOT_TOKEN');
Don’t forget to wrap command execution in player.context.provide(). This allows the useMainPlayer() and useQueue() hooks to work properly.

Project Structure

Your final project structure should look like this:
my-music-bot/
├── commands/
│   ├── play.js
│   ├── skip.js
│   ├── pause.js
│   ├── stop.js
│   └── queue.js
├── index.js
├── package.json
└── .env

Running Your Bot

1

Deploy Commands

Register your slash commands with Discord:
deploy-commands.js
const { REST, Routes } = require('discord.js');
const fs = require('fs');
const path = require('path');

const commands = [];
const commandsPath = path.join(__dirname, 'commands');
const commandFiles = fs
  .readdirSync(commandsPath)
  .filter(file => file.endsWith('.js'));

for (const file of commandFiles) {
  const command = require(path.join(commandsPath, file));
  commands.push(command.data.toJSON());
}

const rest = new REST().setToken('YOUR_BOT_TOKEN');

(async () => {
  try {
    console.log('Started refreshing application (/) commands.');

    await rest.put(
      Routes.applicationCommands('YOUR_CLIENT_ID'),
      { body: commands }
    );

    console.log('Successfully reloaded application (/) commands.');
  } catch (error) {
    console.error(error);
  }
})();
Run: node deploy-commands.js
2

Start Your Bot

node index.js
You should see:
Extractors loaded successfully
Logged in as YourBot#1234
3

Test the Bot

  1. Join a voice channel in your Discord server
  2. Use /play never gonna give you up to play a song
  3. Try other commands like /skip, /pause, /queue

What’s Next?

Congratulations! You’ve built a working music bot. Here are some next steps:

Audio Filters

Learn how to apply audio filters like bass boost and nightcore

Queue Management

Explore advanced queue features like shuffle and repeat modes

Custom Extractors

Create custom extractors for additional audio sources

Events

Discover all available events for better control

Troubleshooting

Bot doesn’t join the voice channel

  • Make sure you have the GuildVoiceStates intent enabled
  • Check that the bot has permission to connect to the voice channel
  • Verify that you’re in a voice channel when using the play command

No audio is playing

  • Ensure FFmpeg is properly installed and accessible
  • Check that you’ve installed an opus library (mediaplex)
  • Verify extractors are loaded: check console for “Extractors loaded successfully”

Commands not working

  • Make sure you’ve registered the slash commands using deploy-commands.js
  • Wrap command execution in player.context.provide() as shown above
  • Check the console for error messages

”Cannot find module” errors

  • Run npm install to ensure all dependencies are installed
  • Check that file paths in require() statements are correct
  • Verify that the commands folder exists and contains the command files
Use player.scanDeps() to generate a dependency report that can help troubleshoot installation issues.

Build docs developers (and LLMs) love