A Discord music bot powered by Lavalink. Simple to deploy, easy to use.
- Features
- Quick Start
- Commands
- Configuration
- Managing the Bot
- Troubleshooting
- Built With
- Contributing
- Links
- License
- Play music from YouTube, SoundCloud, Bandcamp, Twitch, and Vimeo
- Optional Spotify support (search and resolve via YouTube)
- Autoplay mode for continuous music playback
- Queue management with shuffle, loop, and play-next
- Interactive search with track selection
- Deploy-time language selection (English, Spanish, Turkish, Italian, Brazilian Portuguese)
- Role-based access control
- Runs entirely in Docker, no host dependencies
- Works without a self-hosted Lavalink server (automatic public server fallback)
- A Discord bot token from the Developer Portal
- Docker installed
When creating your bot, enable all 3 Privileged Gateway Intents (Presence, Server Members, Message Content).
Uses the pre-built GHCR image, no cloning needed.
1. Create a project directory:
mkdir beatdock && cd beatdock2. Create .env:
TOKEN=your_discord_bot_token3. Create docker-compose.yml:
services:
bot:
container_name: beatdock
image: ghcr.io/lazaroagomez/beatdock:latest
depends_on:
lavalink:
condition: service_healthy
networks:
- beatdock-network
env_file: .env
lavalink:
container_name: beatdock-lavalink
image: ghcr.io/lavalink-devs/lavalink:4
ports:
- "2333:2333"
networks:
- beatdock-network
volumes:
- ./application.yml:/opt/Lavalink/application.yml:ro
environment:
- LAVALINK_PASSWORD=${LAVALINK_PASSWORD:-youshallnotpass}
- SPOTIFY_ENABLED=${SPOTIFY_ENABLED:-false}
- SPOTIFY_CLIENT_ID=${SPOTIFY_CLIENT_ID:-}
- SPOTIFY_CLIENT_SECRET=${SPOTIFY_CLIENT_SECRET:-}
healthcheck:
test: ["CMD", "/bin/bash", "-c", "echo > /dev/tcp/localhost/2333"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
networks:
beatdock-network:
name: beatdock_network4. Create application.yml:
server:
port: 2333
address: 0.0.0.0
plugins:
youtube:
enabled: true
allowSearch: true
allowDirectVideoIds: true
allowDirectPlaylistIds: true
clients:
- MUSIC
- WEB
- ANDROID_VR
lavalink:
plugins:
- dependency: "dev.lavalink.youtube:youtube-plugin:1.16.0"
snapshot: false
server:
password: "${LAVALINK_PASSWORD:youshallnotpass}"
sources:
youtube: false
soundcloud: true
bandcamp: true
twitch: true
vimeo: true
http: false
local: false
bufferDurationMs: 200
frameBufferDurationMs: 1000
youtubePlaylistLoadLimit: 3
playerUpdateInterval: 2
trackStuckThresholdMs: 5000
useSeekGhosting: true
ratelimit:
retryLimit: 5
logging:
level:
root: INFO
lavalink: INFO5. Deploy:
docker compose up -dgit clone https://github.com/lazaroagomez/BeatDock.git
cd BeatDockCreate .env with your credentials (see .env.example for all options):
TOKEN=your_discord_bot_tokendocker compose up -dBeatDock can run without a self-hosted Lavalink server. If LAVALINK_HOST, LAVALINK_PORT, and LAVALINK_PASSWORD are not set, the bot automatically fetches free public Lavalink v4 servers and connects to one. User search queries and track requests are sent to the selected public node. Set PUBLIC_NODE_HOST_ALLOWLIST if you only trust specific public Lavalink hosts.
To use public servers, simply comment out the Lavalink variables in your .env:
# LAVALINK_HOST=lavalink
# LAVALINK_PORT=2333
# LAVALINK_PASSWORD=youshallnotpass| Command | Description |
|---|---|
/play <query> [next] |
Play a song (optionally add to front of queue) |
/search <query> |
Search and select tracks |
/pause |
Pause/resume |
/skip |
Skip track |
/back |
Previous track |
/stop |
Stop and disconnect |
/queue |
Show queue |
/shuffle |
Shuffle queue |
/autoplay |
Toggle autoplay mode |
/loop |
Toggle loop mode |
/clear |
Clear queue |
/volume <1-100> |
Set volume |
/lyrics |
Show lyrics for the current song |
/filter |
Apply audio effects and EQ presets |
/nowplaying |
Current track info |
/invite |
Get bot invite link |
/about |
Bot info |
All configuration is done through the .env file. Only TOKEN is required.
| Variable | Default | Description |
|---|---|---|
TOKEN |
- | Discord bot token (required) |
SPOTIFY_ENABLED |
false |
Enable Spotify search support |
SPOTIFY_CLIENT_ID |
- | Spotify app client ID |
SPOTIFY_CLIENT_SECRET |
- | Spotify app client secret |
DEFAULT_LANGUAGE |
en |
Global bot language for this deployment (en, es, tr, it, pt-BR) |
DEFAULT_VOLUME |
80 |
Default playback volume (0-100) |
AUTOPLAY_DEFAULT |
false |
Enable autoplay by default when music starts |
ALLOWED_ROLES |
- | Comma-separated role IDs to restrict access |
DEFAULT_SEARCH_PLATFORM |
ytmsearch |
Default search platform for user queries |
LAVALINK_PASSWORD |
youshallnotpass |
Lavalink server password |
PUBLIC_NODE_HOST_ALLOWLIST |
- | Optional comma-separated host or *.domain allowlist for public Lavalink fallback |
QUEUE_EMPTY_DESTROY_MS |
30000 |
Disconnect after queue empties (ms) |
EMPTY_CHANNEL_DESTROY_MS |
60000 |
Disconnect from empty channel (ms) |
docker compose logs -f # View logs
docker compose restart # Restart
docker compose down # Stop
docker compose pull && docker compose up -d # UpdateRaspberry Pi 5 (Debian 13) may use a 16KB memory page size, which is incompatible with Lavalink's DAVE encryption library. Check with:
getconf PAGE_SIZEIf the result is not 4096, add kernel=kernel8.img under the [all] section in /boot/firmware/config.txt, then reboot and restart the containers. See #109 for details.
- discord.js - Discord API client
- Lavalink - Audio player server
- lavalink-client - Lavalink client library
- Docker - Containerized deployment
- Node.js 22+ - Runtime
Contributions are welcome. Bug fixes, new features, translations, docs - all good. Check the guide below to get started.
See CONTRIBUTING.md for setup instructions and guidelines.