Migrating to v2.0

Changing to v2.0 represents different breaking changes we needed to make. We did not only needed to fork the original discord.py repository but adapt changes in the Discord API in order of supporting its latest features, to work with threads, buttons and commands.


  • Methods and attributes that returned TextChannel, etc can now return Thread.

  • Python 3.8 or newer is required.

  • Attributes that returned Asset are renamed, e.g. attributes ending with _url (i.e. avatar_url) are changed to avatar.url. User.avatar returns None in case the default avatar is used.

  • on_presence_update() replaces on_member_update() for updates to Member.status and Member.activities.

  • datetime is now timezone-aware.

  • Sticker changes: StickerType has been renamed to StickerFormatType, and the type of Message.stickers is changed. Sticker.preview_image, Sticker.image and Sticker.tags are removed.

  • Webhooks are changed significantly: WebhookAdapter is removed, and synchronous requests using requests is now inside SyncWebhook.

  • edit method no longer updates cache and instead returns modified instance.

  • User accounts (userbots) are no longer supported.

  • Client.logout is removed; use Client.close() instead.

  • on_private_channel_create/delete events are removed.

  • User.permissions_in is removed; use abc.GuildChannel.permissions_in() instead.

  • Message.type for replies are now MessageType.reply.

  • Reaction.custom_emoji property is changed to Reaction.is_custom_emoji method.

  • missing_perms attributes and arguments are renamed to missing_permissions.

  • Many method arguments now reject None.

  • Many arguments are now specified as positional-only or keyword-only; e.g. oauth_url() now takes keyword-only arguments, and methods starting with get_ or fetch_ take positional-only arguments.

  • You must explicitly enable the message_content intent to receive message content, embeds, attachments, and components in most messages.

  • Guild.bans() is no longer a coroutine and returns an AsyncIterator instead of a list.

  • StoreChannel is removed as it is deprecated by Discord, see here for more info.

  • ChannelType.store is removed.

  • AppInfo.summary, AppInfo.guild_id, AppInfo.primary_sku_id and AppInfo.slug are removed.

  • PartialAppInfo.summary is removed.

  • abc.Messageable.pins() has been extracted out from abc.Messageable and moved to PinsMixin

  • VoiceChannel now inherits from Messageable


Webhook changes

Webhook was overhauled.

Webhook and WebhookMessage are now always asynchronous. For synchronous use (requests), use SyncWebhook and SyncWebhookMessage. WebhookAdapter, AsyncWebhookAdapter, and RequestsWebhookAdapter are removed, since they are unnecessary. adapter arguments of Webhook.partial() and Webhook.from_url() are removed. Sessions are now passed directly to partial/from_url.

webhook = nextcord.SyncWebhook.from_url(
webhook.send("Hello from nextcord!")
async with aiohttp.ClientSession() as session:
    webhook = nextcord.Webhook.partial(
    await webhook.send("Hello from nextcord!")

Asset changes

Assets have been changed.

avatar_url = user.display_avatar.url # previously str(avatar_url)
avatar_128x128_url = user.display_avatar.with_size(128).url # previously str(avatar_url_as(size=128))
avatar_128x128_png_url = user.display_avatar.replace(size=128, static_format="png").url
# previously str(avatar_url_as(size=128, static_format="png"))
# The code above can also be written as:
avatar_128x128_png_url = user.display_avatar.with_size(128).with_static_format("png").url

avatar_bytes = await user.display_avatar.read() # previously avatar_url.read

# Emoji and Sticker are special case:
emoji_url = emoji.url # previously str(emoji.url)
emoji_32x32_url = emoji.with_size(32).url # previously str(emoji.url_as(size=32))
emoji_32x32_png_url = emoji.replace(size=32, static_format="png").url
# previously str(url_as(size=128, static_format="png"))

emoji_bytes = await emoji.read() # previously emoji.url.read
# Same applies to Sticker and PartialEmoji.

Python Version Change

In order to make development easier, the library had to remove support for Python versions lower than 3.8, which essentially means that support for Python 3.7, 3.6 and 3.5 is dropped. We recommend updating to Python version 3.9.

Use of timezone-aware time

TL;DR: utils.utcnow() becomes now(datetime.timezone.utc). If you are constructing datetime yourself, pass tzinfo=datetime.timezone.utc.

embed = discord.Embed(
    title = "Pi Day 2021 in UTC",
    timestamp = datetime(2021, 3, 14, 15, 9, 2, tzinfo=timezone.utc)

Note that newly-added nextcord.utils.utcnow() can be used as an alias of datetime.datetime.now(datetime.timezone.utc).

Embed.__bool__ change

Embed that has a value is always considered truthy. Previously it only considered text fields.

Duplicate registration of cogs

commands.Bot.add_cog now raises when a cog with the same name is already registered. override argument can be used to bring back the 1.x behavior.

Message.type for replies

Message.type now returns MessageType.reply for replies, instead of default.


commands.Command.clean_params is now a dict, not collections.OrderedDict.


DMChannel.recipient is now optional, and will return None in many cases.

permissions_for positional only argument

abc.GuildChannel.permissions_for() method’s first argument is now positional only.


Colour.blurple() is renamed to Colour.og_blurple(), and Colour.blurple() now returns the different color.

oauth_url taking keyword only arguments

utils.oauth_url()’s permissions, guild, redirect_uri, and scopes arguments are now keyword only.

StageChannel changes

Due to the introduction of StageInstance representing the current session of a StageChannel,

StageChannel.edit() can no longer edit topic. Use StageInstance.edit() instead. StageChannel.clone() no longer clones its topic.


Message.channel can now return Thread.

Guild methods taking positional only arguments

Guild.get_channel(), Guild.get_role(), Guild.get_member_named(), Guild.fetch_member(), and Guild.fetch_emoji() methods’ first arguments are now positional only.

Guild.create_text_channel topic argument

Guild.create_text_channel()’s topic argument no longer accepts None.


Reaction.custom_emoji is now a method called Reaction.is_custom_emoji for consistency.

Reaction.users arguments keyword only

Arguments of Reaction.users are now keyword only.


IntegrationAccount.id is now str, instead of int, due to Discord changes.

BadInviteArgument new required argument

commands.BadInviteArgument now requires one argument, argument.


missing_perms arguments and attributes of commands.MissingPermissions and commands.BotMissingPermissions are renamed to missing_permissions.


Guild.vanity_invite can now return None.

abc.Messageable.fetch_message positional only

Its first argument is now positional only.

get_partial_message positional only

Its first argument is now positional only.

Template.edit name argument

Template.edit()’s name argument no longer accepts None.

Member.edit roles argument

Member.edit()’s roles argument no longer accepts None.

CommandOnCooldown new required argument

commands.CommandOnCooldown now requires an additional argument, type.


Client.fetch_channel() and Guild.fetch_channel() can now return Thread.

on_member_update and on_presence_update separation

on_member_update() event is no longer dispatched for status/activity changes. Use on_presence_update() instead.


Message.stickers is now List[StickerItem] instead of List[Sticker]. While StickerItem supports some operations of previous Sticker, description and pack_id attributes do not exist. Sticker can be fetched via StickerItem.fetch() method.


AuditLogDiff.type is now Union[ChannelType, StickerType], instead of ChannelType.


commands.ChannelNotReadable.argument can now return Thread.


commands.NSFWChannelRequired.channel can now return Thread.

Bot.add_listener and Bot.remove_listener

commands.Bot.add_listener and commands.Bot.remove_listener’s name arguments no longer accept None.

Context attributes

The following Context attributes can now be None: prefix, command, invoked_with, invoked_subcommand. Note that while the documentation change suggests potentially breaking change, the code indicates that this was always the case.


commands.Command.help can now be None.


Client.get_channel() can now return Thread.

Client methods taking positional only arguments

Client.get_guild(), Client.get_user(), and Client.get_emoji() methods’ first arguments are now positional only.

edit method behavior

edit methods of most classes no longer update the cache in-place, and instead returns the modified object.

on_socket_raw_receive behavior

on_socket_raw_receive() is no longer dispatched for incomplete data, and the value passed is always decompressed and decoded to str. Previously, when received a multi-part zlib-compressed binary message, on_socket_raw_receive() was dispatched on all messages with the compressed, encoded bytes.

Guild.get_member taking positional only argument

Guild.get_member() method’s first argument is now positional only.

Intents.message_content must be enabled to receive message content

In order to receive message content in most messages, you must have Intents.message_content enabled.

You can do this by using Intents.all() or by setting message_content to True:

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

For more information go to the message content intent documentation.

Guild.bans now returns an AsyncIterator

Guild.bans() returns an AsyncIterator instead of a list.

# before
bans = await guild.bans()

# now
bans = await guild.bans().flatten()  # get a list of the first 1000 bans
bans = await guild.bans(limit=None).flatten()  # get a list of all bans


User account support

User account (“userbot”) is no longer supported. Thus, these features that were only applicable to them are removed:

  • bot argument of Client.start/run

  • afk argument of Client.change_presence()

  • Classes: Profile, Relationship, CallMessage, GroupCall

  • RelationshipType, HypeSquadHouse, PremiumType, UserContentFilter, FriendFlags, Theme

  • GroupChannel.add_recipients, remove_recipients, edit (NOTE: GroupChannel itself still remains)

  • Guild.ack

  • Client.fetch_user_profile

  • Message.call and ack

  • ClientUser.email, premium, premium_type, get_relationship, relationships, friends, blocked, create_group, edit_settings

  • ClientUser.edit()’s password, new_password, email, house arguments

  • User.relationship, mutual_friends, is_friend, is_blocked, block, unblock, remove_friend, send_friend_request, profile

  • Events: on_relationship_add and on_relationship_update

This means that detection of Nitro is no longer possible.


This method was an alias of Client.close(), which remains.


This always returned None for compatibility.


Due to Discord changes, this cache flag is no longer available. MemberCacheFlags’s online argument is removed for similar reasons.


Deprecated since 1.5.


These events will no longer be dispatched due to Discord changes.

User.permissions_in, Member.permissions_in

Use abc.GuildChannel.permissions_for() instead.

guild_subscriptions argument

guild_subscriptions argument of Client is replaced with intents system.

fetch_offline_members argument

This argument of Client was an alias of chunk_guilds_at_startup since 1.5.


This was moved to commandsContext.clean_prefix.


This was removed as Discord no longer provides the data.

self_bot argument

Bot’s self_bot argument was removed, since userbots are no longer supported.

VerificationLevel attributes

VerificationLevel.table_flip (alias of high) was removed. extreme, very_high, and double_table_flip attributes were removed and replaced with highest.


StickerType, an enum of sticker formats, is renamed to StickerFormatType. Old name is used for a new enum with different purpose (checking if the sticker is guild sticker or Nitro sticker).


Sticker.image is removed. Its URL can be accessed via Sticker.url, just like new Emoji.


Due to the introduction of GuildSticker, Sticker.tags is removed from the parent class Sticker and moved to StandardSticker.tags.


This was renamed to MessageType.chat_input_command due to Discord adding context menu commands.

StoreChannel has been removed

StoreChannel has been removed as it has been deprecated by Discord, see here for more info.

Meta Change

  • Performance of the library has improved significantly (all times with 1 process and 1 AutoShardedBot):


boot up before

boot up now

735 guilds (with chunking)

57s/1.7 GiB RAM

42s/1.4 GiB RAM

27k guilds (with chunking)

477s/8 GiB RAM

303s/7.2 GiB

48k guilds (without chunking)



106k guilds (without chunking)



  • The public API should be completely type-hinted

  • Almost all edit methods now return their updated counterpart rather than doing an in-place edit