Discord.js Bot Memory Management: Keeping Your Bot Lean in 2026
Your Discord bot starts at 80 MB and climbs to 600 MB over two weeks before crashing. This is one of the most common Discord developer experiences. The cause is almost always a combination of Discord.js caching and application-level memory leaks. Here is the systematic approach to fixing it.
Understanding discord.js Caching
discord.js caches guild members, messages, channels, and more in memory by default. For bots in hundreds of servers, this cache grows substantially over time.
Configuring cache limits in your Client constructor:
const { Client, GatewayIntentBits, LimitedCollection } = require('discord.js');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages
// Only enable intents you actually use
],
makeCache: Options.cacheWithLimits({
MessageManager: 50, // Keep only 50 messages per channel (default: 200)
GuildMemberManager: 10, // Only cache 10 members per guild (vs. all)
UserManager: 50, // 50 users globally cached
PresenceManager: 0, // No presence cache (unless you need it)
GuildEmojiManager: 0, // No emoji cache
}),
sweepers: {
messages: {
interval: 3600, // Run sweep hourly
lifetime: 1800 // Remove messages older than 30 minutes
},
users: {
interval: 3600,
filter: () => user => !user.bot && !client.guilds.cache.has(user.id)
}
}
});
Identifying Memory Leaks in Your Code
Common causes of growth over time:
Event listeners not removed:
// LEAK: adds new listener on every message but never removes
client.on('messageCreate', function handler(msg) {
someEmitter.on('event', () => processMsg(msg)) // New listener each time!
})
// FIX: use once() or track and remove listeners
client.on('messageCreate', (msg) => {
const handler = () => processMsg(msg);
someEmitter.once('event', handler);
})
Growing collections/maps:
// LEAK: never cleaned up
const cooldowns = new Map() // grows indefinitely
cooldowns.set(userId, Date.now())
// FIX: clean up after expiry
cooldowns.set(userId, Date.now())
setTimeout(() => cooldowns.delete(userId), 60000)
Monitoring Memory Over Time
// Log memory usage periodically
setInterval(() => {
const used = process.memoryUsage()
console.log(`RSS: ${Math.round(used.rss / 1024 / 1024)}MB, Heap: ${Math.round(used.heapUsed / 1024 / 1024)}MB`)
}, 30 * 60 * 1000) // Every 30 minutes
With PM2, check memory stats:
pm2 show discord-bot # Shows peak and current memory
If memory grows by more than 20 MB per hour, you have a leak. Set max_memory_restart: '300M' in PM2 as a safety net.