I Built a Zero-Dependency Discord.js Package That Creates Temporary Voice Channels Automatically
The Problem Every Discord Bot Developer Faces
You run a gaming server or a community Discord. You want a "Join to Create" feature – users join a specific voice channel, and the bot instantly spawns a private channel for them. When they leave, the channel disappears.
I've written this logic at least 10 times. Every time, the same pain points:
- Handling Discord's rate limits when multiple users join at once
- Recovering channel-owner mappings after bot crashes
- Transferring ownership when the creator leaves
- Deleting empty channels without leaving orphans
I decided to stop copying code between projects and build a proper npm package.
What I Built
discord-dynamic-voice is a zero-dependency, TypeScript-first manager for Discord.js v14 bots. It handles the full lifecycle of dynamic voice channels.
How it works:
- User joins your designated "creator" channel
- Package creates a new voice channel with cloned permissions
- User is moved automatically into their new channel
- Local JSON file stores channelId -> creatorId for crash recovery
- When empty, channel self-destructs
Key features:
- Rate-limit safe request queue (prevents Discord 429 errors)
- Automatic owner handover if the creator leaves
- Spam prevention cooldowns per user
- Full TypeScript support with type definitions
- Event hooks: channelCreated, channelEmpty, ownerSwapped, error
- Slash command handlers: rename, limit, lock, unlock
Why This Matters
Most Discord bot developers rewrite the same voiceStateUpdate snippet for every project. Those snippets break with every Discord API update.
This package is actively maintained, versioned, and tested across Node.js 18, 20, and 22.
Installation
npm install discord-dynamic-voice
npm install discord.js@^14.0.0
Basic Usage
const { Client, GatewayIntentBits } = require('discord.js');
const { DynamicVoiceManager } = require('discord-dynamic-voice');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildVoiceStates
]
});
const voiceManager = new DynamicVoiceManager(client, {
creatorChannelId: '123456789012345678',
defaultName: "{username}'s space",
autoDeleteWhenEmpty: true
});
voiceManager.on('channelCreated', (channel, creator) => {
console.log(${creator.tag} created ${channel.name});
});
client.on('ready', async () => {
await voiceManager.init();
console.log(Bot ready);
});
client.login('YOUR_TOKEN');
Slash Commands
const { handleRename, handleLimit, handleLock, handleUnlock } = require('discord-dynamic-voice');
if (commandName === 'rename') {
await handleRename(voiceManager, interaction, channel, interaction.member);
}
Crash Recovery
If your bot restarts while dynamic channels are active, the package:
- Reads the local JSON state file
- Checks which channels still exist
- Re-associates them with their owners
- Deletes any truly orphaned channels
No more ghost channels cluttering your server.
Links
npm: https://www.npmjs.com/package/discord-dynamic-voice
GitHub: https://github.com/Lavvordev/discord-dynamic-voice
Try it out. Star the repo. Stop rewriting voiceStateUpdate.
Top comments (0)