Discord.js & Discord.py — How to Make a Discord Bot with Basic Commands (2025)
In this comprehensive tutorial, you'll learn how to create a fully functional Discord bot using both discord.js (JavaScript/Node.js) and discord.py (Python). We'll cover setup, basic commands, and several useful features with complete code examples you can use right away.
discord.js vs discord.py — Which Should You Choose?
Both libraries are excellent choices for building Discord bots. Here's a quick comparison:
| Feature | discord.js | discord.py |
|---|---|---|
| Language | JavaScript (Node.js) | Python |
| Difficulty | Beginner-friendly | Very beginner-friendly |
| Performance | Excellent (async) | Very good (async) |
| Community | Very large | Very large |
| Slash Commands | Built-in support | Built-in support |
If you already know Python, start with discord.py. If you prefer JavaScript or want a larger ecosystem, go with discord.js.
Part 1: discord.js Bot Setup
Installation
Make sure you have Node.js 16 or higher installed. Then create a new folder for your project and run:
npm init -y
npm install discord.js dotenv
Create a .env file to store your bot token:
TOKEN=your_bot_token_here
Basic discord.js Bot with Multiple Commands
require('dotenv').config();
const { Client, GatewayIntentBits, EmbedBuilder } = require('discord.js');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildMembers,
GatewayIntentBits.MessageContent,
],
});
const PREFIX = '!';
client.once('ready', () => {
console.log(`✅ ${client.user.tag} is online!`);
client.user.setActivity('dlist.space | !help', { type: 'WATCHING' });
});
client.on('messageCreate', async (message) => {
if (message.author.bot) return;
if (!message.content.startsWith(PREFIX)) return;
const args = message.content.slice(PREFIX.length).trim().split(/ +/);
const command = args.shift().toLowerCase();
// !ping command
if (command === 'ping') {
const sent = await message.reply('Pinging...');
sent.edit(`🏓 Pong! Latency: ${sent.createdTimestamp - message.createdTimestamp}ms`);
}
// !help command
if (command === 'help') {
const embed = new EmbedBuilder()
.setTitle('📖 Command List')
.setColor(0x5865F2)
.addFields(
{ name: '!ping', value: 'Check bot latency', inline: true },
{ name: '!help', value: 'Show this menu', inline: true },
{ name: '!userinfo [@user]', value: 'Get user information', inline: true },
{ name: '!serverinfo', value: 'Get server information', inline: true },
{ name: '!kick [@user] [reason]', value: 'Kick a member (Admin)', inline: true },
{ name: '!ban [@user] [reason]', value: 'Ban a member (Admin)', inline: true },
{ name: '!clear [amount]', value: 'Delete messages (Mod)', inline: true },
{ name: '!avatar [@user]', value: "Get user's avatar", inline: true },
)
.setFooter({ text: 'Bot powered by discord.js' });
message.reply({ embeds: [embed] });
}
// !userinfo command
if (command === 'userinfo') {
const target = message.mentions.members.first() || message.member;
const embed = new EmbedBuilder()
.setTitle(`👤 User Info — ${target.user.username}`)
.setThumbnail(target.user.displayAvatarURL())
.setColor(0x5865F2)
.addFields(
{ name: 'Username', value: target.user.username, inline: true },
{ name: 'User ID', value: target.user.id, inline: true },
{ name: 'Joined Discord', value: target.user.createdAt.toDateString(), inline: true },
{ name: 'Joined Server', value: target.joinedAt.toDateString(), inline: true },
{ name: 'Roles', value: target.roles.cache.map(r => r.name).join(', ') || 'None' },
);
message.reply({ embeds: [embed] });
}
// !serverinfo command
if (command === 'serverinfo') {
const guild = message.guild;
const embed = new EmbedBuilder()
.setTitle(`🏠 ${guild.name}`)
.setThumbnail(guild.iconURL())
.setColor(0x5865F2)
.addFields(
{ name: 'Members', value: guild.memberCount.toString(), inline: true },
{ name: 'Channels', value: guild.channels.cache.size.toString(), inline: true },
{ name: 'Roles', value: guild.roles.cache.size.toString(), inline: true },
{ name: 'Owner', value: `<@${guild.ownerId}>`, inline: true },
{ name: 'Created', value: guild.createdAt.toDateString(), inline: true },
);
message.reply({ embeds: [embed] });
}
// !avatar command
if (command === 'avatar') {
const target = message.mentions.users.first() || message.author;
const embed = new EmbedBuilder()
.setTitle(`🖼️ ${target.username}'s Avatar`)
.setImage(target.displayAvatarURL({ size: 512 }))
.setColor(0x5865F2);
message.reply({ embeds: [embed] });
}
// !kick command
if (command === 'kick') {
if (!message.member.permissions.has('KickMembers')) {
return message.reply('❌ You do not have permission to kick members.');
}
const target = message.mentions.members.first();
if (!target) return message.reply('❌ Please mention a member to kick.');
const reason = args.slice(1).join(' ') || 'No reason provided';
await target.kick(reason);
message.reply(`✅ ${target.user.username} was kicked. Reason: ${reason}`);
}
// !ban command
if (command === 'ban') {
if (!message.member.permissions.has('BanMembers')) {
return message.reply('❌ You do not have permission to ban members.');
}
const target = message.mentions.members.first();
if (!target) return message.reply('❌ Please mention a member to ban.');
const reason = args.slice(1).join(' ') || 'No reason provided';
await target.ban({ reason });
message.reply(`✅ ${target.user.username} was banned. Reason: ${reason}`);
}
// !clear command
if (command === 'clear') {
if (!message.member.permissions.has('ManageMessages')) {
return message.reply('❌ You do not have permission to delete messages.');
}
const amount = parseInt(args[0]);
if (isNaN(amount) || amount < 1 || amount > 100) {
return message.reply('❌ Please provide a number between 1 and 100.');
}
await message.channel.bulkDelete(amount + 1, true);
const confirm = await message.channel.send(`✅ Deleted ${amount} messages.`);
setTimeout(() => confirm.delete(), 3000);
}
});
client.login(process.env.TOKEN);
Part 2: discord.py Bot Setup
Installation
Make sure you have Python 3.8 or higher installed. Install discord.py:
pip install discord.py python-dotenv
Create a .env file:
TOKEN=your_bot_token_here
Basic discord.py Bot with Multiple Commands
import discord
from discord.ext import commands
import os
from dotenv import load_dotenv
load_dotenv()
TOKEN = os.getenv('TOKEN')
intents = discord.Intents.default()
intents.message_content = True
intents.members = True
bot = commands.Bot(command_prefix='!', intents=intents)
@bot.event
async def on_ready():
print(f'✅ {bot.user} is online!')
await bot.change_presence(activity=discord.Activity(
type=discord.ActivityType.watching,
name='dlist.space | !help'
))
@bot.command()
async def ping(ctx):
"""Check bot latency"""
await ctx.reply(f'🏓 Pong! Latency: {round(bot.latency * 1000)}ms')
@bot.command()
async def userinfo(ctx, member: discord.Member = None):
"""Get information about a user"""
member = member or ctx.author
embed = discord.Embed(title=f'👤 User Info — {member.name}', color=0x5865F2)
embed.set_thumbnail(url=member.avatar.url)
embed.add_field(name='Username', value=member.name, inline=True)
embed.add_field(name='User ID', value=member.id, inline=True)
embed.add_field(name='Joined Discord', value=member.created_at.strftime('%Y-%m-%d'), inline=True)
embed.add_field(name='Joined Server', value=member.joined_at.strftime('%Y-%m-%d'), inline=True)
roles = [r.name for r in member.roles if r.name != '@everyone']
embed.add_field(name='Roles', value=', '.join(roles) or 'None', inline=False)
await ctx.reply(embed=embed)
@bot.command()
async def serverinfo(ctx):
"""Get information about the server"""
guild = ctx.guild
embed = discord.Embed(title=f'🏠 {guild.name}', color=0x5865F2)
if guild.icon:
embed.set_thumbnail(url=guild.icon.url)
embed.add_field(name='Members', value=guild.member_count, inline=True)
embed.add_field(name='Channels', value=len(guild.channels), inline=True)
embed.add_field(name='Roles', value=len(guild.roles), inline=True)
embed.add_field(name='Created', value=guild.created_at.strftime('%Y-%m-%d'), inline=True)
await ctx.reply(embed=embed)
@bot.command()
async def avatar(ctx, member: discord.Member = None):
"""Get a user's avatar"""
member = member or ctx.author
embed = discord.Embed(title=f"🖼️ {member.name}'s Avatar", color=0x5865F2)
embed.set_image(url=member.avatar.url)
await ctx.reply(embed=embed)
@bot.command()
@commands.has_permissions(kick_members=True)
async def kick(ctx, member: discord.Member, *, reason='No reason provided'):
"""Kick a member from the server"""
await member.kick(reason=reason)
await ctx.reply(f'✅ {member.name} was kicked. Reason: {reason}')
@bot.command()
@commands.has_permissions(ban_members=True)
async def ban(ctx, member: discord.Member, *, reason='No reason provided'):
"""Ban a member from the server"""
await member.ban(reason=reason)
await ctx.reply(f'✅ {member.name} was banned. Reason: {reason}')
@bot.command()
@commands.has_permissions(manage_messages=True)
async def clear(ctx, amount: int):
"""Delete a number of messages"""
if amount < 1 or amount > 100:
return await ctx.reply('❌ Please provide a number between 1 and 100.')
await ctx.channel.purge(limit=amount + 1)
msg = await ctx.send(f'✅ Deleted {amount} messages.')
await asyncio.sleep(3)
await msg.delete()
@kick.error
@ban.error
async def permission_error(ctx, error):
if isinstance(error, commands.MissingPermissions):
await ctx.reply('❌ You do not have permission to use this command.')
bot.run(TOKEN)
Adding Slash Commands (discord.js)
Slash commands are the modern way to interact with Discord bots. Here's how to add a basic slash command using discord.js:
const { SlashCommandBuilder } = require('discord.js');
// In your commands folder, create ping.js:
module.exports = {
data: new SlashCommandBuilder()
.setName('ping')
.setDescription('Check bot latency'),
async execute(interaction) {
await interaction.reply(`🏓 Pong! Latency: ${interaction.client.ws.ping}ms`);
},
};
Next Steps
Now that you have a working bot with basic commands, here's what to learn next:
- Database integration — Store user data with MongoDB or SQLite
- Slash commands — Use modern application commands
- Embeds and buttons — Create rich, interactive responses
- Cogs/Modules — Organize commands into separate files
- Economy system — Add currency and shop commands
- Music playback — Stream audio from YouTube
Share Your Bot on dlist.space
Once your bot is ready, list it on dlist.space to share it with the Discord community and start growing your user base!