How to Make a Discord Economy Bot — Currency, Balance & Shop (2025)
Discord economy bots are among the most popular bot types on Discord. They add a fun virtual currency system to your server where members can earn coins, buy items from a shop, gamble, and compete on leaderboards. In this tutorial, we'll build a complete Discord economy bot with discord.js.
Economy Commands We'll Build
- !balance / !bal — Check your coin balance
- !daily — Claim daily coins (once per 24 hours)
- !work — Work to earn coins
- !pay — Send coins to another user
- !shop — View the item shop
- !buy — Buy an item from the shop
- !inventory — View your purchased items
- !leaderboard / !lb — View richest users
- !coinflip / !cf — Gamble your coins
- !rob — Attempt to rob another user
Complete Discord.js Economy Bot Code
require('dotenv').config();
const { Client, GatewayIntentBits, EmbedBuilder } = require('discord.js');
const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent],
});
// In-memory database (use MongoDB or SQLite in production)
const economy = new Map();
const dailyCooldown = new Map();
const workCooldown = new Map();
const robCooldown = new Map();
const SHOP = [
{ id: 1, name: '🎩 Top Hat', price: 500, description: 'A fancy top hat' },
{ id: 2, name: '🚗 Sports Car', price: 5000, description: 'Vroom vroom' },
{ id: 3, name: '🏠 House', price: 20000, description: 'A cozy home' },
{ id: 4, name: '✨ VIP Role', price: 10000, description: 'Exclusive VIP status' },
];
function getUser(userId) {
if (!economy.has(userId)) {
economy.set(userId, { balance: 0, bank: 0, inventory: [] });
}
return economy.get(userId);
}
function addCoins(userId, amount) {
const user = getUser(userId);
user.balance += amount;
}
function removeCoins(userId, amount) {
const user = getUser(userId);
user.balance = Math.max(0, user.balance - amount);
}
const PREFIX = '!';
client.on('messageCreate', async (message) => {
if (message.author.bot || !message.content.startsWith(PREFIX)) return;
const args = message.content.slice(PREFIX.length).trim().split(/ +/);
const command = args.shift().toLowerCase();
// BALANCE command
if (command === 'balance' || command === 'bal') {
const target = message.mentions.users.first() || message.author;
const user = getUser(target.id);
const embed = new EmbedBuilder()
.setTitle(`💰 ${target.username}'s Balance`)
.setColor(0xf59e0b)
.addFields(
{ name: 'Wallet', value: `🪙 ${user.balance.toLocaleString()} coins`, inline: true },
{ name: 'Bank', value: `🏦 ${user.bank.toLocaleString()} coins`, inline: true },
{ name: 'Total', value: `💎 ${(user.balance + user.bank).toLocaleString()} coins`, inline: true },
);
message.reply({ embeds: [embed] });
}
// DAILY command
if (command === 'daily') {
const cooldownKey = `${message.author.id}-daily`;
const lastUsed = dailyCooldown.get(cooldownKey);
const now = Date.now();
const cooldown = 24 * 60 * 60 * 1000; // 24 hours
if (lastUsed && now - lastUsed < cooldown) {
const remaining = cooldown - (now - lastUsed);
const hours = Math.floor(remaining / 3600000);
const minutes = Math.floor((remaining % 3600000) / 60000);
return message.reply(`⏰ Daily already claimed! Come back in ${hours}h ${minutes}m.`);
}
const reward = Math.floor(Math.random() * 200) + 100; // 100-300 coins
addCoins(message.author.id, reward);
dailyCooldown.set(cooldownKey, now);
message.reply(`✅ Daily claimed! You received 🪙 ${reward} coins!`);
}
// WORK command (1 hour cooldown)
if (command === 'work') {
const cooldownKey = message.author.id;
const lastUsed = workCooldown.get(cooldownKey);
const now = Date.now();
const cooldown = 60 * 60 * 1000; // 1 hour
if (lastUsed && now - lastUsed < cooldown) {
const remaining = Math.ceil((cooldown - (now - lastUsed)) / 60000);
return message.reply(`⏰ You're tired! Rest for ${remaining} more minutes.`);
}
const jobs = ['programmer', 'artist', 'chef', 'teacher', 'driver', 'doctor'];
const job = jobs[Math.floor(Math.random() * jobs.length)];
const earned = Math.floor(Math.random() * 150) + 50;
addCoins(message.author.id, earned);
workCooldown.set(cooldownKey, now);
message.reply(`💼 You worked as a ${job} and earned 🪙 ${earned} coins!`);
}
// PAY command
if (command === 'pay') {
const target = message.mentions.users.first();
if (!target) return message.reply('❌ Please mention a user to pay.');
if (target.id === message.author.id) return message.reply('❌ You cannot pay yourself.');
const amount = parseInt(args[1]);
if (isNaN(amount) || amount <= 0) return message.reply('❌ Please enter a valid amount.');
const sender = getUser(message.author.id);
if (sender.balance < amount) return message.reply(`❌ You only have 🪙 ${sender.balance} coins.`);
removeCoins(message.author.id, amount);
addCoins(target.id, amount);
message.reply(`✅ Sent 🪙 ${amount} coins to ${target.username}!`);
}
// SHOP command
if (command === 'shop') {
const embed = new EmbedBuilder()
.setTitle('🛒 Item Shop')
.setColor(0x5865F2)
.setDescription('Use !buy - to purchase an item.')
.addFields(SHOP.map(item => ({
name: `#${item.id} ${item.name} — 🪙 ${item.price.toLocaleString()}`,
value: item.description,
})));
message.reply({ embeds: [embed] });
}
// BUY command
if (command === 'buy') {
const itemId = parseInt(args[0]);
const item = SHOP.find(i => i.id === itemId);
if (!item) return message.reply('❌ Item not found. Use !shop to see available items.');
const user = getUser(message.author.id);
if (user.balance < item.price) {
return message.reply(`❌ You need 🪙 ${item.price} coins but only have 🪙 ${user.balance}.`);
}
if (user.inventory.includes(item.name)) {
return message.reply('❌ You already own this item.');
}
removeCoins(message.author.id, item.price);
user.inventory.push(item.name);
message.reply(`✅ Purchased ${item.name} for 🪙 ${item.price} coins!`);
}
// INVENTORY command
if (command === 'inventory' || command === 'inv') {
const user = getUser(message.author.id);
const embed = new EmbedBuilder()
.setTitle(`🎒 ${message.author.username}'s Inventory`)
.setColor(0x5865F2)
.setDescription(user.inventory.length > 0 ? user.inventory.join('\n') : 'Your inventory is empty.');
message.reply({ embeds: [embed] });
}
// LEADERBOARD command
if (command === 'leaderboard' || command === 'lb') {
const sorted = [...economy.entries()]
.sort(([, a], [, b]) => (b.balance + b.bank) - (a.balance + a.bank))
.slice(0, 10);
const medals = ['🥇', '🥈', '🥉'];
const embed = new EmbedBuilder()
.setTitle('🏆 Richest Members')
.setColor(0xf59e0b)
.setDescription(
(await Promise.all(sorted.map(async ([id, data], i) => {
const user = await client.users.fetch(id).catch(() => ({ username: 'Unknown' }));
return `${medals[i] || `${i + 1}.`} **${user.username}** — 🪙 ${(data.balance + data.bank).toLocaleString()}`;
}))).join('\n')
);
message.reply({ embeds: [embed] });
}
// COINFLIP command
if (command === 'coinflip' || command === 'cf') {
const bet = parseInt(args[0]);
if (isNaN(bet) || bet <= 0) return message.reply('❌ Enter a valid bet amount.');
const user = getUser(message.author.id);
if (user.balance < bet) return message.reply(`❌ Not enough coins. You have 🪙 ${user.balance}.`);
const won = Math.random() > 0.5;
if (won) {
addCoins(message.author.id, bet);
message.reply(`🪙 **Heads!** You won 🪙 ${bet} coins!`);
} else {
removeCoins(message.author.id, bet);
message.reply(`🪙 **Tails!** You lost 🪙 ${bet} coins!`);
}
}
});
client.login(process.env.TOKEN);
Adding a Database (MongoDB)
For a production-ready economy bot, replace the in-memory Map with MongoDB:
npm install mongoose
const mongoose = require('mongoose');
mongoose.connect(process.env.MONGODB_URI);
const userSchema = new mongoose.Schema({
userId: String,
balance: { type: Number, default: 0 },
bank: { type: Number, default: 0 },
inventory: [String],
lastDaily: Date,
lastWork: Date,
});
const User = mongoose.model('User', userSchema);
List Your Economy Bot
Economy bots are extremely popular on Discord. Once yours is ready, list it on dlist.space under the Economy tag and watch your server count grow!