After major music bots (Rythm, Groovy) were shut down by Google, self-hosted music bots became the standard. Here's how to build one that works reliably.
Why Self-Hosted
| Factor | Public Bot | Self-Hosted | |--------|-----------|-------------| | Reliability | Shared load, outages | Your server, your uptime | | Audio quality | Often compressed | Full quality | | Features | Limited | Whatever you build | | Privacy | Your data on their server | Your data stays with you | | Cost | Free (with limitations) | Hosting cost |
Technical Setup
Dependencies
For Node.js (discord.js):
npm install discord.js @discordjs/voice @discordjs/opus sodium-native play-dl
For Python (discord.py):
pip install discord.py[voice] yt-dlp
Both require FFmpeg installed on the system:
apt install ffmpeg
Basic Music Bot (Node.js)
const { Client, GatewayIntentBits } = require('discord.js');
const { joinVoiceChannel, createAudioPlayer, createAudioResource } = require('@discordjs/voice');
const play = require('play-dl');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent
]
});
const queue = new Map();
client.on('messageCreate', async (message) => {
if (message.content.startsWith('!play')) {
const query = message.content.slice(6);
const voiceChannel = message.member.voice.channel;
if (!voiceChannel) {
return message.reply('Join a voice channel first!');
}
const connection = joinVoiceChannel({
channelId: voiceChannel.id,
guildId: message.guild.id,
adapterCreator: message.guild.voiceAdapterCreator
});
const stream = await play.stream(query);
const resource = createAudioResource(stream.stream, {
inputType: stream.type
});
const player = createAudioPlayer();
player.play(resource);
connection.subscribe(player);
message.reply(`Now playing: ${query}`);
}
});
Queue System
A proper music bot needs a queue:
class MusicQueue {
constructor() {
this.songs = [];
this.playing = false;
}
add(song) {
this.songs.push(song);
}
next() {
return this.songs.shift();
}
clear() {
this.songs = [];
}
get length() {
return this.songs.length;
}
}
Essential Commands
| Command | Action | |---------|--------| | !play [query] | Search and play a song | | !skip | Skip current track | | !queue | Show upcoming songs | | !pause | Pause playback | | !resume | Resume playback | | !volume [1-100] | Adjust volume | | !leave | Disconnect from voice |
Audio Quality
Bitrate Settings
Discord voice channels support different bitrates:
| Channel Quality | Bitrate | Server Boost Level | |----------------|---------|-------------------| | Standard | 64 kbps | None | | Improved | 128 kbps | Level 1 | | High | 256 kbps | Level 2 | | Best | 384 kbps | Level 3 |
Your bot should encode audio at the channel's maximum supported bitrate for best quality.
Audio Processing
Add equalizer and volume normalization:
# FFmpeg filter for loudness normalization
-af "loudnorm=I=-14:TP=-1:LRA=11,equalizer=f=100:width_type=h:width=200:g=3"
This normalizes volume between tracks (no jarring volume changes) and adds a subtle bass boost.
Hosting Requirements
| Feature | CPU | RAM | |---------|-----|-----| | 1 voice connection | 0.2 cores | 100MB | | 5 voice connections | 1 core | 300MB | | 10 voice connections | 2 cores | 500MB |
Music bots are surprisingly lightweight. The FFmpeg encoding uses some CPU, but a single voice connection barely registers on modern hardware.
Space-Node's Discord bot hosting handles music bot workloads easily, even on the free Small plan for single-server bots. For bots serving multiple servers simultaneously, the Middle or Large plan provides the resources for concurrent voice connections.
Self-hosted music bots give you control over your audio experience. No arbitrary shutdowns, no quality limitations, and no dependence on a service that might disappear tomorrow.
