Skip to main content
Pycord is a modern, maintained fork of discord.py that continues to receive updates and support for new Discord features. This guide will help you migrate from discord.py to Pycord.

Why Migrate to Pycord?

Pycord offers several advantages over discord.py:
  • Active Development: Regular updates with new Discord features
  • Modern Discord Features: Slash commands, buttons, select menus, modals, and more
  • Community Support: Active Discord community and documentation
  • Backward Compatibility: Maintains compatibility with discord.py syntax
  • Full API Coverage: Supports the latest Discord API features

Installation

pip uninstall discord.py
Important: Uninstall discord.py before installing Pycord to avoid conflicts. Both libraries use the discord namespace.

Import Changes

Good news! Most imports remain the same:
# These imports work in both discord.py and Pycord
import discord
from discord.ext import commands, tasks
from discord import app_commands  # For slash commands
No import changes are needed for basic functionality.

Python Version Support

# Requires Python 3.8+
Python 3.8 - 3.11 supported
Pycord 2.7+ requires Python 3.10 or higher. If you’re using Python 3.8 or 3.9, you’ll need to upgrade Python or use Pycord 2.6.

Bot Setup Comparison

The basic bot setup is nearly identical:
import discord
from discord.ext import commands

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

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

@bot.event
async def on_ready():
    print(f"Logged in as {bot.user}")

@bot.command()
async def ping(ctx):
    await ctx.send("Pong!")

bot.run("TOKEN")
As you can see, the code is identical! Your existing discord.py bot should work with minimal changes.

Slash Commands

Both libraries support slash commands, but with different syntax:
import discord
from discord import app_commands
from discord.ext import commands

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

@bot.tree.command(name="hello", description="Say hello")
async def hello(interaction: discord.Interaction, name: str):
    await interaction.response.send_message(f"Hello {name}!")

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

bot.run("TOKEN")
Note: Pycord’s discord.Bot automatically syncs slash commands. You don’t need to manually call sync().

Slash Command Options

from discord import app_commands
import discord

@bot.tree.command()
@app_commands.describe(
    user="The user to greet",
    message="Custom message"
)
async def greet(
    interaction: discord.Interaction,
    user: discord.User,
    message: str = "Hello"
):
    await interaction.response.send_message(f"{message}, {user.mention}!")

UI Components

Both libraries support buttons, select menus, and modals with similar syntax:

Buttons

import discord
from discord.ui import Button, View

class MyView(View):
    @discord.ui.button(label="Click me!", style=discord.ButtonStyle.primary)
    async def button_callback(self, interaction: discord.Interaction, button: Button):
        await interaction.response.send_message("Button clicked!", ephemeral=True)

@bot.command()
async def buttons(ctx):
    view = MyView()
    await ctx.send("Click the button:", view=view)
Minor Difference: Note the parameter order in button callbacks. Pycord typically uses (button, interaction) while discord.py uses (interaction, button).

Select Menus

import discord
from discord.ui import Select, View

class MyView(View):
    @discord.ui.select(
        placeholder="Choose an option...",
        options=[
            discord.SelectOption(label="Option 1", value="1"),
            discord.SelectOption(label="Option 2", value="2"),
        ]
    )
    async def select_callback(self, interaction: discord.Interaction, select: Select):
        await interaction.response.send_message(f"You selected: {select.values[0]}")

Modals

import discord
from discord.ui import Modal, TextInput

class MyModal(Modal, title="Feedback Form"):
    feedback = TextInput(label="Your feedback", style=discord.TextStyle.paragraph)

    async def on_submit(self, interaction: discord.Interaction):
        await interaction.response.send_message(f"Thanks for your feedback: {self.feedback.value}")

@bot.tree.command()
async def feedback(interaction: discord.Interaction):
    await interaction.response.send_modal(MyModal())
Difference: Pycord uses InputText instead of TextInput, and InputTextStyle instead of TextStyle.

Context Differences

Interaction Responses

# Responding to interactions
await interaction.response.send_message("Hello!")
await interaction.followup.send("Follow-up message")

# Deferring
await interaction.response.defer()
await interaction.followup.send("Done!")
Pycord provides ctx.respond() as a more intuitive alternative to interaction.response.send_message().

Cogs

Cog syntax is nearly identical:
from discord.ext import commands
from discord import app_commands

class MyCog(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    @commands.command()
    async def hello(self, ctx):
        await ctx.send("Hello from cog!")

    @app_commands.command()
    async def slash_hello(self, interaction: discord.Interaction):
        await interaction.response.send_message("Hello from slash command!")

async def setup(bot):
    await bot.add_cog(MyCog(bot))

Renamed Classes and Methods

Emoji Changes

emoji = discord.Emoji(...)  # Guild emoji

Bot Class

# Text commands
bot = commands.Bot(command_prefix="!")

# Slash commands
bot = commands.Bot(command_prefix="!", intents=intents)
# Use bot.tree for slash commands

Bridge Commands (Pycord Exclusive)

Pycord offers a unique feature: Bridge Commands that work as both text and slash commands:
from discord.ext import bridge

bot = bridge.Bot(command_prefix="!")

@bot.bridge_command()
async def hello(ctx, name: str):
    await ctx.respond(f"Hello {name}!")

# Works as both:
# !hello World (text command)
# /hello World (slash command)
This feature doesn’t exist in discord.py!

Event Handling

Event handling is identical in both libraries:
@bot.event
async def on_ready():
    print(f"Logged in as {bot.user}")

@bot.event
async def on_message(message):
    if message.author == bot.user:
        return
    
    if message.content.startswith("hello"):
        await message.channel.send("Hi!")
    
    await bot.process_commands(message)  # Important for commands!

@bot.event
async def on_member_join(member):
    await member.send(f"Welcome to {member.guild.name}!")

Permissions and Intents

Both libraries handle intents the same way:
import discord

# Default intents
intents = discord.Intents.default()

# Enable specific intents
intents.message_content = True  # Required for message commands
intents.members = True          # Privileged intent
intents.presences = True        # Privileged intent

# All intents (not recommended)
intents = discord.Intents.all()

bot = discord.Bot(intents=intents)
Remember to enable privileged intents in the Discord Developer Portal for members, presences, and message_content.

Voice Support

Voice functionality works identically:
@bot.command()
async def join(ctx):
    if ctx.author.voice:
        channel = ctx.author.voice.channel
        await channel.connect()
    else:
        await ctx.send("You're not in a voice channel!")

@bot.command()
async def leave(ctx):
    if ctx.voice_client:
        await ctx.voice_client.disconnect()

Key Advantages of Pycord

1. Simpler Slash Commands

Pycord’s discord.Bot makes slash commands more intuitive than discord.py’s app_commands.CommandTree.

2. Bridge Commands

Unique to Pycord - support both text and slash commands with one decorator.

3. Active Development

Pycord receives regular updates with new Discord features:
  • Polls support
  • Voice messages
  • Forum channels
  • Soundboard support
  • And more!

4. Better Documentation

Pycord has dedicated documentation and an active community.

5. ctx.respond()

More intuitive than interaction.response.send_message().

Common Pitfalls

Callback Parameter Order

Pycord and discord.py sometimes use different parameter orders in UI callbacks:
# Pycord
async def button_callback(self, button, interaction):
    pass

# discord.py
async def button_callback(self, interaction, button):
    pass

InputText vs TextInput

Pycord uses InputText, discord.py uses TextInput:
# Pycord
from discord.ui import InputText

# discord.py
from discord.ui import TextInput

Sync() Not Needed

Pycord automatically syncs slash commands. Don’t call bot.tree.sync().

Python Version

Make sure you’re using Python 3.10+ for Pycord 2.7+.

Migration Checklist

  • Uninstall discord.py: pip uninstall discord.py
  • Install Pycord: pip install py-cord
  • Update Python to 3.10+ if needed
  • Test existing commands (most should work without changes)
  • Update slash command syntax if using app_commands
  • Update UI callback parameter order if needed
  • Replace TextInput with InputText in modals
  • Remove bot.tree.sync() calls if using discord.Bot
  • Update Emoji to GuildEmoji for clarity (optional)
  • Test all functionality thoroughly
  • Consider using Bridge Commands for dual support
  • Update your documentation and README

Side-by-Side Example

Here’s a complete bot example in both libraries:
import discord
from discord import app_commands
from discord.ext import commands

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

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

@bot.event
async def on_ready():
    await bot.tree.sync()
    print(f"Logged in as {bot.user}")

@bot.command()
async def ping(ctx):
    await ctx.send("Pong!")

@bot.tree.command(name="hello")
async def hello(interaction: discord.Interaction, name: str):
    await interaction.response.send_message(f"Hello {name}!")

bot.run("TOKEN")

Getting Help

If you need help migrating: Welcome to the Pycord community!

Build docs developers (and LLMs) love