Releases: discord-jda/JDA
v6.0.0-rc.5 | Modal Components and Serialization
Overview
This release adds support for more components in Modals and reintroduces serialization for all components.
Modal Components (#2913)
In the previous release, support for StringSelectMenu
within modals has been added. This is now expanded to also include EntitySelectMenu
and TextDisplay
components.
The TextDisplay
component has full markdown support, which allows you to create more fleshed out modals than before:
Modal.create("modal", "Role Request Form")
.addComponents(
TextDisplay.of("""
**Welcome!**
Please read the following before continuing:
- Select a user to request a role for
- A moderator will review your request
- Abuse of this system may result in penalties
"""),
Label.of(
"Role",
EntitySelectMenu.create("role-select", SelectTarget.ROLE).build()
)
)
.build();
Results in this modal being shown:

Serialization and Deserialization (#2906)
We've added a new ComponentSerializer
and ComponentDeserializer
, which can be used to serialize components into DataObject
and FileUpload
instances. This replaces the previous component.toData()
from JDA 5, with a new serializer.serialize(component)
.
Example:
ComponentSerializer serializer = new ComponentSerializer();
List<DataObject> serializedComponents = serializer.serializeAll(message.getComponents());
List<FileUpload> files = serializer.getFileUploads(message.getComponents());
// use serialized component
// ...
// Or deserialize them if you get them from another source
// Here we pass in the List<FileUpload> used by the components
ComponentDeserializer deserializer = new ComponentDeserializer(files);
MessageComponentTree tree = deserializer.deserializeAsTree(MessageComponentTree.class, serializedComponents);
New Features
- Add ComponentSerializer and ComponentDeserializer by @MinnDevelopment in #2906
- Add TextInput#of shortcut by @MinnDevelopment in #2908
- Add
StringSelectMenu.Builder#isRequired()
by @freya022 in #2911 - Add entity selects and text displays in modals by @freya022 in #2913
Changes
Bug Fixes
- Remove unnecessary escaping while creating a masked link by @Alf-Melmac in #2910
Full Changelog: v6.0.0-rc.4...v6.0.0-rc.5
Installation
Gradle
repositories {
mavenCentral()
}
dependencies {
implementation("net.dv8tion:JDA:6.0.0-rc.5")
}
Maven
<dependency>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>6.0.0-rc.5</version>
</dependency>
v6.0.0-rc.4 | Change to Modals
Overview
This release primarily introduces breaking changes to Modals. Discord has finally added support for StringSelectMenu
in Modals, which comes with a minor breaking change in how Modals are created.

Breaking Changes
With the update to Modals, we removed legacy functionality around ActionRow
in Modal
. Instead of using ActionRow.of(...)
, modals make use of the new Label components instead.
Before:
Modal.create("modal", "My Modal")
.addComponents(
ActionRow.of(TextInput.create("input", "My Custom Label", TextInputStyle.SHORT).build()))
.build();
After:
Modal.create("modal", "My Modal")
.addComponents(
Label.of("My Custom Label", TextInput.create("input", TextInputStyle.SHORT).build()))
.build();
With this update, you can now also use StringSelectMenu
in Modals, which can also be added using the Label
component.
Label.of("My Custom Label",
StringSelectMenu.create("menu-custom-id")
.addOption("My option", "option-1")
.build())
When a user submits a modal with a select menu, the values are available in the ModalInteractionEvent
using getValue("menu-custom-id").getAsStringList()
.
New Features
Bug Fixes
- Serialize unique id for text inputs by @MineKing9534 in #2899
- Handle forum channels with missing available_tags field by @MinnDevelopment in #2902
Full Changelog: v6.0.0-rc.3...v6.0.0-rc.4
Installation
Gradle
repositories {
mavenCentral()
}
dependencies {
implementation("net.dv8tion:JDA:6.0.0-rc.4")
}
Maven
<dependency>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>6.0.0-rc.4</version>
</dependency>
v6.0.0-rc.3 | New pin permissions and removal of bot owned guilds
Overview
Another release candidate for JDA 6.0.0 with some more minor breaking changes. Modal features have been moved to a new package and functionality to bot owned guilds has been removed, including Guild#delete
, Guild#transferOwnership
, JDA#createGuild
, and GuildManager#setMFALevel
.
This release candidate also includes some underlying API changes and bug fixes that are backwards compatible, as well as some minor feature additions.
Breaking Changes
Some of these changes have been integrated into the 6.0.0 OpenRewrite recipe, please re-apply it if necessary. See the release notes for 6.0.0-rc.1 for details.
- Move modal classes out of the
interactions
package by @freya022 in #2890 - Remove bot owned guild endpoints by @freya022 in #2888
New Features
- Add message pin permission by @freya022 in #2895
- Add support for user primary guilds by @mjezek-dev in #2863
- Add common interface for interactions with a custom ID by @Kaktushose in #2778
Other Changes
Bug Fixes
- Remove port stripping in VoiceServerUpdateHandler by @MinnDevelopment in #2884
- Several Components V2 changes by @freya022 in #2881
Full Changelog: v6.0.0-rc.2...v6.0.0-rc.3
Installation
Gradle
repositories {
mavenCentral()
}
dependencies {
implementation("net.dv8tion:JDA:6.0.0-rc.3")
}
Maven
<dependency>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>6.0.0-rc.3</version>
</dependency>
v6.0.0-rc.2 | New Pin Pagination API
Overview
This release includes a minor breaking change to the retrievePinnedMessages
method.
Originally, this method could only fetch up to 50 pinned messages. However, the underlying endpoint has been deprecated and replaced with a new paginated endpoint, as detailed in the Discord Changelog.
We have updated our API to utilize a PaginationAction
. The callback response is now a list of PinnedMessage
objects instead of a list of messages. Each PinnedMessage
instance contains the timestamp when the message was pinned and the pinned message object. With this pagination action, the retrieval of pinned messages is no longer limited to 50 messages and can now fetch more, for instance by using takeAsync(200)
.
To replicate the previous behavior (retrieving only up to 50 pinned messages), you can use queue()
as before, but you will need to map the list to a List<Message>
as follows:
channel.retrievePinnedMessages()
.map(list -> list.stream().map(PinnedMessage::getMessage).toList())
.queue(list -> ...);
Changes
- Make JDA#getMutualGuilds accept UserSnowflake instead of User objects by @MineKing9534 in #2877
- Add new pinned message pagination by @MinnDevelopment in #2874
Full Changelog: v6.0.0-rc.1...v6.0.0-rc.2
Installation
Gradle
repositories {
mavenCentral()
}
dependencies {
implementation("net.dv8tion:JDA:6.0.0-rc.2")
}
Maven
<dependency>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>6.0.0-rc.2</version>
</dependency>
v6.0.0-rc.1 | New Components
Overview
Warning
This is the first release candidate for JDA 6.0.0. The major version bump reflects several breaking changes to the message and modal component APIs. Additional breaking changes may still be introduced before the final stable release of 6.0.0.
This version introduces support for Components Version 2, a significant update to Discord's component system. To accommodate this new API, we’ve made a number of key changes to our component implementation:
-
All components are now immutable
Previously,ActionRow
allowed modification of its contained components. To simplify and modernize the API, this mutability has been removed. -
New top-level component interfaces
TheLayoutComponent
interface (previously only implemented byActionRow
) has been replaced by two new interfaces:
-MessageTopLevelComponent
-ModalTopLevelComponent
This change reflects the increased flexibility introduced in Components V2, where top-level components are no longer restricted to layout containers likeActionRow
. Components such asTextDisplay
andFileDisplay
can now appear directly at the top level. -
Renamed
getId
→getCustomId
The originalgetId
method has been renamed togetCustomId
to avoid confusion with Discord's newgetUniqueId
, which is a numeric, auto-generated identifier. -
Temporary removal of
toData
for components
Some components now require attachments to function properly, complicating serialization. We’ve removed thetoData
method for now and are working on a new, more capable serialization API that will be introduced in a later update.
Big thanks to @freya022 and @DV8FromTheWorld for contributing on this giant feature!
Using Components V2
To use the new components introduced in this release, you must enable the Components V2 feature flag on your message request. This can be done using the useComponentsV2
method on MessageRequest
.
Tip
Enabling this flag comes with certain limitations, so we strongly recommend reviewing the documentation for important details before integrating it into your project.
To get started, check out the new ComponentsV2Example to explore the possibilities of this updated API. You can also see it in action in a demo project by @DV8FromTheWorld: discord-pokedex.

New Components
JDA 6 introduces several new component types as part of the Components V2 system:
-
Container
Displays components inside a visually distinct box — similar to how embeds are styled. -
Thumbnail
Shows a small image next to text. Commonly used as an accessory within aSection
component. -
FileDisplay
Displays a file attachment as a downloadable item. For visual file content (e.g., images), consider usingMediaGallery
instead. -
MediaGallery
Shows multiple images in a gallery layout — similar to a list of image attachments in Discord. -
Section
Displays a block of text content with optional accessories like thumbnails or buttons. -
Separator
Adds vertical spacing between components, helping visually organize content. -
TextDisplay
A simple text component used to display content without relying on thecontent
field of a message.
Note
Components that use files, such as FileDisplay
or MediaGallery
, will automatically attach files as message attachments in your requests.
New Utilities For Components
Several new utilities have been added to simplify working with complex component structures — including traversal, replacement, and deserialization:
-
MessageComponentTree
&ModalComponentTree
A single object that provides the functionality to iterate and replace components easily. -
ComponentReplacer
An interface for removing or replacing components within a tree or collection.
For example, remove a component by unique ID usingbyUniqueId(1, null)
. -
ComponentIterator
&ComponentPathIterator
Tools for recursively iterating through nested components, including child elements like buttons within anActionRow
. -
Components
A utility class used for parsing serialized JSON into JDA's component model.
Migrating To 6.0.0
To help ease the upgrade to JDA 6.0.0, we've provided an OpenRewrite recipe that can automatically refactor parts of your codebase. This will update imports and replace a few method calls with their new equivalents in JDA 6.0.0.
However, not all breaking changes can be handled automatically — for example, code that relied on the mutability of ActionRow
will require manual adjustments.
The OpenRewrite Recipe
Before applying the recipe, make sure you’re using version control (e.g., Git) or back up your project manually. You’ll also need to be using Gradle or Maven to apply the migration.
Gradle
We are using the OpenRewrite Gradle Plugin. Before changing your JDA version in gradle, you can add the rewrite plugin and use the recipe to migrate your code:
plugins {
id("org.openrewrite.rewrite") version "7.11.0"
}
repositories {
mavenCentral()
}
dependencies {
// Your current JDA version before upgrading to 6.0.0
implementation("net.dv8tion:JDA:5.+")
// The current 6.0.0 release version
rewrite("net.dv8tion:JDA:6.0.0-rc.1")
rewrite("org.openrewrite.recipe:rewrite-java-dependencies:1.37.0")
}
rewrite {
activeRecipe("net.dv8tion.MigrateComponentsV2")
}
Once you configured this plugin, you can use the rewriteDryRun
task to generate a git patch in build/reports/rewrite/rewrite.patch
to see what the plugin will do with your source code. To apply the changes, either use this patch or use rewriteRun
.
After migrating your code, you can then update your JDA version (if the rewrite hasn't done it already) and remove the plugin again.
Maven
We are using the OpenRewrite Maven Plugin. Before changing your JDA version in your pom, you can add the rewrite plugin and use the recipe to migrate your code:
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>6.13.0</version>
<configuration>
<activeRecipes>
<recipe>net.dv8tion.MigrateComponentsV2</recipe>
</activeRecipes>
</configuration>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-java-dependencies</artifactId>
<version>1.37.0</version>
</dependency>
<dependency>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>6.0.0-rc.1</version>
</dependency>
</dependencies>
</plugin>
Once you configured this plugin, you can use the rewrite:dryRun
task to generate a git patch in target/site/rewrite/rewrite.patch
to see what the plugin will do with your source code. To apply the changes, either use this patch or use rewrite:run
.
After migrating your code, you can then update your JDA version (if the rewrite hasn't done it already) and remove the plugin again.
The ComponentReplacer
If you previously used LayoutComponent.updateComponents
or changed an action row with the mutable getComponents()
, you will have to migrate your code to the new ComponentReplacer instead.
Before:
List<LayoutComponent> components = message.getComponents();
LayoutComponent.updateComponent(
components,
"my-component-id",
Button.primary("button-id", "Click me").asDisabled()
);
After:
MessageComponentTree components = message.getComponentTree();
...
v5.6.1
Bug Fixes
- Remove check for isWebhookMessage in checkUser by @MinnDevelopment in #2857
Full Changelog: v5.6.0...v5.6.1
Installation
Gradle
repositories {
mavenCentral()
}
dependencies {
implementation("net.dv8tion:JDA:5.6.1")
}
Maven
<dependency>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>5.6.1</version>
</dependency>
v5.6.0 | ApplicationManager and minor improvements
Overview
This release introduces the ApplicationManager, which can be used to update the application's description and other settings through JDA.
New Features
- Implement application manager by @MinnDevelopment and @raul1ro in #2854
- Require a
UserSnowflake
inmoveVoiceMember
andkickVoiceMember
by @freya022 in #2852
Changes
- Add
with_components=true
query param to WebhookClient requests by @Xirado in #2850 - Set thread ID when manipulating message objects made by webhooks by @freya022 in #2849
Bug Fixes
- Fix message content intent warning being logged when accessing messag… by @Xirado in #2851
- Handle new voice websocket close codes by @MinnDevelopment in #2855
Full Changelog: v5.5.1...v5.6.0
Installation
Gradle
repositories {
mavenCentral()
}
dependencies {
implementation("net.dv8tion:JDA:5.6.0")
}
Maven
<dependency>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>5.6.0</version>
</dependency>
v5.5.1 | Bug fixes and performance improvements
Overview
This is a small release, including a bug fix for editCommand
and editCommandById
, as well as some performance improvements for looking up members by roles.
Additionally, you can now create threads with a custom slowmode.
New Features
- Add
AbstractThreadCreateAction#setSlowmode
by @replaceitem in #2842 - Add Member#getUnsortedRoles by @MinnDevelopment in #2841
Bug Fixes
- Fix editCommandById by @MinnDevelopment in #2839
Full Changelog: v5.5.0...v5.5.1
Installation
Gradle
repositories {
mavenCentral()
}
dependencies {
implementation("net.dv8tion:JDA:5.5.1")
}
Maven
<dependency>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>5.5.1</version>
</dependency>
v5.5.0 | Improved voice state cache and file proxies
Changes to voice state cache (#2835)
Voice states are now cached independently of guild members. JDA can now detect when a member connects or disconnects from an audio channel, even when the member is not currently cached.
With this change, you can technically use MemberCachePolicy.NONE
and will still receive voice join / leave events, as long as CacheFlag.VOICE_STATE
is enabled.
To reduce the memory footprint, we now only cache voice states if the member is connected to an audio channel. While disconnected, we will not keep the voice state cached, meaning we lose track of muted/deafend state and return an "empty" voice state for Member#getVoiceState
.
Improvements to FileProxy (#2782 and #2727)
The FileProxy, ImageProxy, and AttachmentProxy now all support downloadAsFileUpload to easily stream a Discord proxies URL to a message.
@Override
public void onMessageReceived(MessageReceivedEvent event) {
List<Message.Attachment> attachments = event.getMessage().getAttachments();
List<FileUpload> uploads = attachments.stream()
.map(attachment ->
attachment
.getProxy()
.downloadAsFileUpload(attachment.getWidth(), attachment.getHeight()))
.collect(Collectors.toList());
event.getChannel().sendFiles(uploads).queue();
}
New Features
- Add
downloadAsFileUpload
to file proxies by @freya022 in #2782 - Add
ImageProxy#downloadAsIcon
by @freya022 in #2727
Changes
- Move voice state cache to guild by @MinnDevelopment in #2835
Bug Fixes
- Allow \ in invite links by @rtm516 in #2796
- Fix checks in CommandEditAction by @MinnDevelopment in #2837
Full Changelog: v5.4.0...v5.5.0
Installation
Gradle
repositories {
mavenCentral()
}
dependencies {
implementation("net.dv8tion:JDA:5.5.0")
}
Maven
<dependency>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>5.5.0</version>
</dependency>
v5.4.0 | Interaction callback response and security incidents
Access the created or updated message from interaction replies (#2798)
You can now use InteractionHook#getCallbackResponse to access the messages created by interaction replies.
@Override
public void onSlashCommandInteraction(SlashCommandInteractionEvent event) {
event.reply("React with your favorite emoji")
.map(hook -> hook.getCallbackResponse().getMessage())
.flatMap(message -> message.addReaction(emoji))
.queue();
}
Previously, this could be done using an additional retrieveOriginal
request. To reduce requests and improve responsiveness, we recommend preferring this new getter instead.
Guild security incidents (#2577)
With guild security incidents, you can now be aware when Discord detects raids or spam in direct messages in a guild. These detections are available with Guild#getSecurityIncidentDetections and are updated with GuildUpdateSecurityIncidentDetectionsEvent.
Additionally, you can modify the security incident actions to temporarily pause invites or disable direct messages in your guild. See Guild#modifySecurityIncidents for details.
guild.modifySecurityIncidents(SecurityIncidentActions.enabled(
// Pause invites for 2 hours
OffsetDateTime.now().plusHours(2),
// Disable direct messages for 1 hour
OffsetDateTime.now().plusHours(1)
)).queue();
// Or disable security incident actions prematurely
guild.modifySecurityIncidents(SecurityIncidentActions.disabled()).queue();
New Features
- Add interaction callback response handling by @Xirado in #2798
- Add support for guild security incidents by @MinnDevelopment in #2577
- Add a way to retrieve users that used super reaction by @MTM123 in #2786
- Add Guild#retrieveScheduledEvents by @senseiwells in #2800
Changes
Bug Fixes
- Prevent firing voice state update events if member is not cached by @freya022 in #2773
- Fix
FileProxy#withClient
return types by @freya022 in #2698
Full Changelog: v5.3.2...v5.4.0
Installation
Gradle
repositories {
mavenCentral()
}
dependencies {
implementation("net.dv8tion:JDA:5.4.0")
}
Maven
<dependency>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>5.4.0</version>
</dependency>