Back to Blog
How to Make a Discord Economy Bot — Currency, Balance & Shop (2025)
Tutorial June 8, 2025 13 min read dlist.space Team
discord economy bot discord currency bot discord coins bot discord shop bot discord bot economy system

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.

Discord Economy Bot Tutorial

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!