Python Discord Bot Development — Core Concepts

Why this matters in production

Discord has over 200 million monthly active users and has expanded far beyond gaming. Companies use it for developer communities (Midjourney, Hugging Face), customer support, and internal communication. Bots are central to the Discord ecosystem — they handle moderation, onboarding, content delivery, and community engagement at a scale that would be impossible manually.

Python’s discord.py library is the most popular framework for building Discord bots, with a mature async architecture that handles thousands of concurrent events.

How Discord bots connect

Discord bots use a WebSocket connection called the Gateway. When your bot starts, it:

  1. Authenticates with its token via HTTPS.
  2. Opens a WebSocket connection to Discord’s Gateway.
  3. Receives a stream of events (messages, reactions, member joins, voice state changes).
  4. Sends responses back through the REST API (not through the WebSocket).

This is an important distinction: events come in through WebSocket, but actions (sending messages, banning users) go out through HTTP. The WebSocket is read-heavy; the REST API is write-heavy.

Intents: controlling what your bot sees

Discord uses an intent system to control which events your bot receives. This was introduced for privacy and performance — bots should only receive data they actually need.

Common intents:

  • Guilds — Server/channel structure changes
  • Guild Messages — Messages in server channels
  • Guild Members — Member join/leave/update events (privileged)
  • Message Content — Actual text of messages (privileged)
  • Guild Voice States — Voice channel activity

Privileged intents (Members and Message Content) require manual approval in the Discord Developer Portal once your bot is in 100+ servers. Without the Message Content intent, your bot cannot read what people type — it can only respond to slash commands and interactions.

This is why modern Discord bots are moving toward slash commands rather than message-prefix commands (like !help).

Command types

Slash commands appear in Discord’s autocomplete when a user types /. They are:

  • Discoverable — users see available commands without documentation
  • Type-safe — Discord handles argument parsing and validation
  • Permission-controlled — server admins can restrict commands per channel or role
  • No Message Content intent needed

Prefix commands (legacy)

Prefix commands like !help or ?play require reading message content. They are simpler to implement but harder to discover and require the privileged Message Content intent.

For new bots, slash commands are the clear best practice.

The event system

Discord.py is built on Python’s asyncio. Every handler is an async function:

Events your bot can listen for include:

  • on_ready — Bot has connected and is operational
  • on_message — A message was sent (requires Message Content intent)
  • on_member_join — A new member joined the server
  • on_reaction_add — Someone reacted to a message
  • on_voice_state_update — Someone joined, left, or moved voice channels

Each event delivers a payload with relevant data (the message object, the member who joined, etc.).

Permissions and roles

Discord has a granular permission system. Your bot needs permissions to perform actions:

  • Send Messages — Post in channels
  • Manage Messages — Delete or pin messages (for moderation)
  • Kick Members / Ban Members — For moderation bots
  • Connect / Speak — For voice channel bots
  • Manage Roles — For bots that assign roles

Permissions are set at two levels: the bot’s role permissions in the server, and the OAuth permissions requested during installation. Always request the minimum set your bot needs.

Common misconception

Many new developers think a Discord bot runs “on Discord’s servers.” It does not. Your bot runs on your machine (laptop, VPS, Raspberry Pi) and connects to Discord over the internet. If your machine shuts down, the bot goes offline. Discord provides the communication platform; you provide the compute. This is why bot hosting is a real concern — you need a server running 24/7 for the bot to stay online.

Practical architecture

A well-designed Discord bot uses a modular structure:

  1. Cogs — Discord.py’s module system. Each cog is a Python class containing related commands and event listeners. A moderation cog handles bans and mutes. A music cog handles playback. Cogs can be loaded, unloaded, and reloaded at runtime.

  2. Database layer — For persisting data (user levels, server settings, warnings). SQLite for small bots, PostgreSQL for larger ones.

  3. Configuration — Per-server settings (prefix, enabled features, allowed channels) stored in a database and cached in memory.

  4. Error handling — Global error handlers that catch exceptions, log them, and send user-friendly messages instead of crashing.

The one thing to remember: Discord bots are async Python programs that connect via WebSocket, use intents to control data access, and should use slash commands over message prefixes for modern, discoverable interactions.

pythondiscordbotsautomation

See Also

  • Python Email Templating Jinja Discover how Jinja templates let Python create personalized emails for thousands of people without writing each one by hand.
  • Python Imap Reading Emails See how Python reads your inbox using IMAP — explained with a mailbox-and-key analogy anyone can follow.
  • Python Push Notifications How Python sends those buzzing alerts to your phone and browser — explained for anyone who has ever wondered where notifications come from.
  • Python Slack Bot Development Find out how Python builds Slack bots that read messages, reply to commands, and automate team workflows — no Slack expertise needed.
  • Python Smtplib Sending Emails Understand how Python sends emails through smtplib using the simplest real-world analogy you will ever need.