This guide will walk you through creating your first Discord bot using JDA. By the end, you’ll have a working bot that responds to slash commands.
Prerequisites
Install JDA
Make sure you’ve installed JDA in your project using Gradle or Maven.
Create a Discord Application
You’ll need to create a bot account in the Discord Developer Portal .
Click “New Application” and give it a name
Navigate to the “Bot” section
Click “Add Bot”
Copy your bot token (keep this secret!)
Enable the required intents for your bot
Never share your bot token publicly. It provides full access to your bot.
Invite Your Bot
Generate an invite link in the OAuth2 section:
Go to OAuth2 > URL Generator
Select bot and applications.commands scopes
Select the required bot permissions
Copy the generated URL and open it in your browser
Select a server and authorize the bot
Your First Bot: Slash Commands
Let’s create a simple bot that responds to slash commands. This example uses no intents, making it lightweight and easy to start with.
Create the Bot Class
Create a new file SlashBot.java: import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.requests.GatewayIntent;
import java.util.EnumSet;
import static net.dv8tion.jda.api.interactions.commands.OptionType.STRING;
public class SlashBot extends ListenerAdapter {
public static void main ( String [] args ) {
// Slash commands don't need any intents
EnumSet < GatewayIntent > intents = EnumSet . noneOf ( GatewayIntent . class );
JDA jda = JDABuilder . createLight ( "YOUR_BOT_TOKEN" , intents)
. addEventListeners ( new SlashBot ())
. build ();
// Register slash commands
jda . updateCommands (). addCommands (
Commands . slash ( "say" , "Makes the bot say what you tell it to" )
. addOption (STRING, "content" , "What the bot should say" , true )
). queue ();
}
@ Override
public void onSlashCommandInteraction ( SlashCommandInteractionEvent event ) {
if ( event . getName (). equals ( "say" )) {
String content = event . getOption ( "content" , OptionMapping :: getAsString);
event . reply (content). queue ();
}
}
}
Replace YOUR_BOT_TOKEN with your actual bot token from the Discord Developer Portal.
Run Your Bot
Compile and run your bot: javac -cp "path/to/JDA.jar" SlashBot.java
java -cp ".:path/to/JDA.jar" SlashBot
If you’re using an IDE, simply run the main method.
Test Your Bot
In Discord, type /say and you should see your command appear. Enter some text and the bot will repeat it back to you! If you don’t see the command immediately, try reloading Discord (Ctrl+R on desktop).
Understanding the Code
Let’s break down what’s happening:
JDABuilder
JDA jda = JDABuilder . createLight ( "YOUR_BOT_TOKEN" , intents)
. addEventListeners ( new SlashBot ())
. build ();
createLight() creates a lightweight JDA instance with minimal caching
addEventListeners() registers your event listener class
build() starts the bot and connects to Discord
Registering Commands
jda . updateCommands (). addCommands (
Commands . slash ( "say" , "Makes the bot say what you tell it to" )
. addOption (STRING, "content" , "What the bot should say" , true )
). queue ();
This registers a /say command with one required string parameter called content.
Handling Commands
@ Override
public void onSlashCommandInteraction ( SlashCommandInteractionEvent event) {
if ( event . getName (). equals ( "say" )) {
String content = event . getOption ( "content" , OptionMapping :: getAsString);
event . reply (content). queue ();
}
}
This method is called whenever someone uses a slash command. We check the command name and respond accordingly.
Example: Message Logger Bot
For a more complex example, here’s a bot that logs messages to the console:
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.requests.GatewayIntent;
import java.util.EnumSet;
public class MessageLogger extends ListenerAdapter {
public static void main ( String [] args ) {
// This bot needs the MESSAGE_CONTENT privileged intent
EnumSet < GatewayIntent > intents = EnumSet . of (
GatewayIntent . GUILD_MESSAGES ,
GatewayIntent . MESSAGE_CONTENT
);
JDABuilder . createLight ( "YOUR_BOT_TOKEN" , intents)
. addEventListeners ( new MessageLogger ())
. build ();
}
@ Override
public void onMessageReceived ( MessageReceivedEvent event ) {
User author = event . getAuthor ();
Message message = event . getMessage ();
if ( event . isFromGuild ()) {
System . out . printf ( "[%s] [%#s] %#s: %s \n " ,
event . getGuild (). getName (),
event . getChannel (),
author,
message . getContentDisplay ());
} else {
System . out . printf ( "[direct] %#s: %s \n " ,
author,
message . getContentDisplay ());
}
}
}
The MESSAGE_CONTENT intent is privileged and must be explicitly enabled in your bot settings in the Discord Developer Portal.
Gateway Intents
Intents control what events your bot receives. For optimal performance, only enable the intents you need:
GUILD_MESSAGES - Receive message events in servers
DIRECT_MESSAGES - Receive direct message events
MESSAGE_CONTENT - Access message content (privileged)
GUILD_MEMBERS - Access member information (privileged)
GUILD_PRESENCES - Access presence updates (privileged)
RestAction and Queuing
All API requests in JDA use the RestAction interface:
channel . sendMessage ( "Hello!" )
. queue (); // Sends the request asynchronously
You must call queue(), submit(), or complete() to execute the request. Without it, nothing happens!
RestAction Methods
queue() - Execute asynchronously (recommended)
queue(success -> {...}) - Execute with a success callback
submit() - Returns a CompletableFuture<T>
complete() - Execute synchronously (blocking)
Chaining Actions
event . reply ( "Processing..." )
. flatMap (hook -> hook . editOriginal ( "Done!" ))
. queue ();
Next Steps
RestAction Guide Learn how to chain and combine API requests
Interactions Build buttons, select menus, and modals
Event List Explore all available events
Examples Browse more code examples