🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

How to Build a Discord Bot with Python in 2026: Complete Tutorial

⏱️5 min read  ·  902 words

Building a Discord bot is a fun, practical Python project that teaches async programming, APIs, and event handling. In 2026, discord.py makes it straightforward. This guide builds a functional bot with slash commands, embeds, and interactive buttons, then deploys it.

Step 1: Create a Discord Application

  1. Go to the Discord Developer Portal (discord.com/developers)
  2. Click New Application, name your bot
  3. Go to the Bot section, click Add Bot
  4. Copy the Token (keep it secret — never commit it)
  5. Enable Message Content Intent under Privileged Gateway Intents
  6. Under OAuth2, then URL Generator: select bot and applications.commands scopes, choose permissions, and use the generated URL to invite the bot to your server

Step 2: Setup

pip install discord.py python-dotenv

# Project structure
mybot/
├── bot.py
├── .env
└── requirements.txt
# .env — never commit this
DISCORD_TOKEN=your_bot_token_here

Step 3: Basic Bot with Slash Commands

# bot.py
import os
import discord
from discord import app_commands
from discord.ext import commands
from dotenv import load_dotenv

load_dotenv()

intents = discord.Intents.default()
intents.message_content = True

bot = commands.Bot(command_prefix="!", intents=intents)

@bot.event
async def on_ready():
    # Sync slash commands with Discord
    await bot.tree.sync()
    print(f"Logged in as {bot.user}")

# Slash command
@bot.tree.command(name="hello", description="Greet the user")
async def hello(interaction: discord.Interaction):
    await interaction.response.send_message(
        f"Hello, {interaction.user.mention}!"
    )

# Slash command with parameters
@bot.tree.command(name="add", description="Add two numbers")
async def add(interaction: discord.Interaction, a: int, b: int):
    await interaction.response.send_message(f"{a} + {b} = {a + b}")

bot.run(os.getenv("DISCORD_TOKEN"))

Step 4: Rich Embeds

@bot.tree.command(name="userinfo", description="Show user information")
async def userinfo(interaction: discord.Interaction, member: discord.Member = None):
    member = member or interaction.user

    embed = discord.Embed(
        title=f"User Info: {member.display_name}",
        color=discord.Color.blurple()
    )
    embed.set_thumbnail(url=member.display_avatar.url)
    embed.add_field(name="Username", value=str(member), inline=True)
    embed.add_field(name="ID", value=member.id, inline=True)
    embed.add_field(
        name="Joined",
        value=member.joined_at.strftime("%Y-%m-%d"),
        inline=False
    )
    embed.set_footer(text="MyBot")

    await interaction.response.send_message(embed=embed)

Step 5: Interactive Buttons

class ConfirmView(discord.ui.View):
    def __init__(self):
        super().__init__(timeout=60)
        self.value = None

    @discord.ui.button(label="Confirm", style=discord.ButtonStyle.green)
    async def confirm(self, interaction: discord.Interaction, button: discord.ui.Button):
        self.value = True
        await interaction.response.send_message("Confirmed!", ephemeral=True)
        self.stop()

    @discord.ui.button(label="Cancel", style=discord.ButtonStyle.red)
    async def cancel(self, interaction: discord.Interaction, button: discord.ui.Button):
        self.value = False
        await interaction.response.send_message("Cancelled.", ephemeral=True)
        self.stop()

@bot.tree.command(name="confirm", description="Ask for confirmation")
async def confirm_cmd(interaction: discord.Interaction):
    view = ConfirmView()
    await interaction.response.send_message("Are you sure?", view=view)

Step 6: Event Handling

# Welcome new members
@bot.event
async def on_member_join(member):
    channel = member.guild.system_channel
    if channel:
        await channel.send(f"Welcome {member.mention} to the server!")

# React to messages
@bot.event
async def on_message(message):
    if message.author == bot.user:
        return  # ignore the bot's own messages

    if "hello bot" in message.content.lower():
        await message.channel.send("Hello there!")

    await bot.process_commands(message)  # keep prefix commands working

Step 7: Deploy the Bot

# Bots need to run 24/7. Deploy to a small VPS or Railway/Fly.io.

# On a VPS with systemd — /etc/systemd/system/mybot.service
[Unit]
Description=Discord Bot
After=network.target

[Service]
WorkingDirectory=/opt/mybot
ExecStart=/opt/mybot/venv/bin/python bot.py
Restart=always
EnvironmentFile=/opt/mybot/.env

[Install]
WantedBy=multi-user.target

# Enable and start
sudo systemctl enable mybot
sudo systemctl start mybot

Frequently Asked Questions

Q: Slash commands vs prefix commands?
A: Slash commands (/command) are the modern standard — Discord shows them in a menu with parameter hints. Prefix commands (!command) still work but are legacy. Use slash commands for new bots.

Q: Why aren’t my slash commands showing up?
A: You must call bot.tree.sync() to register them with Discord (done in on_ready above). Global sync can take up to an hour to propagate; sync to a specific guild for instant testing.

Q: How do I keep my bot token secure?
A: Store it in a .env file (gitignored), never hardcode it, and never commit it. If leaked, regenerate it immediately in the Developer Portal — a leaked token lets anyone control your bot.

Q: Where should I host my bot for free/cheap?
A: Railway and Fly.io have free/low-cost tiers. A $4-6/month VPS (Hetzner, Contabo) with systemd is reliable and cheap. Avoid free tiers that sleep on inactivity — bots need to run continuously.

Q: How do I add a database to my bot?
A: SQLite for simple bots (via aiosqlite for async), or PostgreSQL for larger ones (asyncpg). Store per-server settings, user data, or command state. Always use async database libraries to avoid blocking the bot.

Conclusion

Building a Discord bot with Python is an approachable project that teaches async programming and API integration. The discord.py library handles the hard parts — you define slash commands, rich embeds, and interactive buttons with clean decorators. Once your bot works locally, deploy it to a small VPS with systemd (or Railway/Fly.io) so it runs 24/7. From here, add a database, more commands, and event handlers to grow your bot into whatever your community needs.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা