Library / SDK
Discord4J/Discord4J avatar
Discord4J/Discord4J

Discord4J blocks where it must, and the Message Content intent decides whether your bot sees anything

Discord4J is a fast, powerful, unopinionated, reactive library to enable quick and easy development of Discord bots for Java, Kotlin, and other JVM languages using the official Discord Bot API.

1,924 stars268 forksJavaLGPL-3.0

At a glance

What is it?
Discord4J is an LGPL-3.0 reactive Java and Kotlin library for building Discord bots on the official Bot API, published as com.discord4j:discord4j-core and split into core, gateway, rest, common, oauth2 and voice modules. Its reactive-streams design means nearly every call returns a Mono you have to block on somewhere.
Who is it for?
Discord4J suits JVM teams that already build with Reactor or Spring and want rate limiting and reconnection handled for them. Verify first that your application has the Message Content intent enabled in the developer portal, since the quick example silently receives empty message content without it, and note that the README's dependency snippets still pin 3.3.0 while the latest release listed is 3.3.3.
Can I use it commercially?
Yes, with conditions. LGPL-3.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Reading a message takes two blocking calls and one portal setting

The quick example captures the basic flow and also shows the cost of the reactive design. Creating the client and logging in are two operations:

java
DiscordClient client = DiscordClient.create(token);
GatewayDiscordClient gateway = client.login().block();

The message handler then does the same thing twice more. message.getChannel() returns a Mono, so the example calls block() to get a MessageChannel before it can create a reply, and createMessage returns a Mono that is blocked as well. Three blocking points in a handler that runs per message, which is a deliberate choice to keep the example readable rather than a rule the library imposes.

The last line is gateway.onDisconnect().block(), and that one is not optional in the same way. Without it the main method returns and the JVM may exit, so the application would connect and then vanish.

The portal setting matters as much as the code. The README instructs you to make sure the bot has the Message Content intent enabled in the developer portal. Without it the string comparison on message.getContent() never matches and the bot appears to run correctly while ignoring every message, which is the single most common way a first Discord4J bot fails.

Gateway intents and the version table are the compatibility contract

Discord4J publishes a version table that maps each line to a Gateway version, an intents policy and an interaction support level, and it is more useful than the prose around it.

The current line, v3.3.x, targets Gateway API v10 with mandatory non-privileged intents as the default and full interaction support. v3.2.x is in maintenance only, targets v8, and also has mandatory non-privileged intents by default. v3.1.x is unsupported: Gateway v6, optional intents with no intent default, and interactions in maintenance only.

Two things follow. First, the intents default is a library decision, not a Discord one, so a bot upgrading from an older line can silently begin receiving events it previously had to opt into, which changes load rather than breaking. Second, interaction support, the feature set behind slash commands, is fully supported only on v3.3.x and v3.2.x, so an unsupported line means no new interaction features.

The repository branches match the table: master is current, 3.2.x is maintenance only, and 3.1.x is unsupported.

One artifact, five build systems, and a version that lags

Installation is one artifact, com.discord4j:discord4j-core, offered for four build tools. The README recommends creating a Gradle project in IntelliJ IDEA and links Maven and Eclipse alternatives. The Gradle form is the shortest:

groovy
repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.discord4j:discord4j-core:3.3.0'
}

Kotlin DSL uses the same coordinate with parentheses, Maven wraps it in a dependency element, and SBT uses libraryDependencies with the percent operator. All four resolve the same artifact from Maven Central, so the choice is purely about your build file.

Note the version. Every snippet in the README pins 3.3.0, and the Javadoc badge in the header points at 3.3.1, while the release list shows 3.3.2 from April 2026 and 3.3.3 from August 2026. Three patch releases have landed since the documented snippet was written, none of them marked as breaking, and the README still shows the older coordinate. For a library at a 3.3.x patch level that is normal, and it means you should read the Migration Guide rather than assume patch releases are free of behaviour change.

Six modules, and modularity aimed at small runtimes

The repository layout is the module list. core/ is the artifact most applications depend on. gateway/ handles the websocket connection and the event stream that gateway.on() subscribes to. rest/ is the HTTP side, oauth2/ covers authorization, common/ holds shared types, and voice/ is the voice channel support.

The stated reason for the split is to let advanced users reach lower levels and build minimal, fast runtimes or add their own abstractions. In practice that means a bot that only sends scheduled messages does not need to carry the voice stack, and a team that wants to replace caching can.

The features that come with the official API integration are named as benefits: automatic rate limiting, automatic reconnection strategies, and consistent naming conventions. Rate limiting is the one that changes your code most, because it is why a burst of messages does not immediately return HTTP 429 to you, and why retry logic in the calling layer is usually unnecessary.

For large deployments the README points outside the core library: Discord4J connect for custom distribution frameworks, and a Stores repository with off-heap caching backed by Redis. Neither is part of the main artifact, which is worth knowing before you plan an architecture on them.

Reactor is the substrate, which is both the draw and the cost

Discord4J follows the reactive-streams protocol, and the README states the goal as running smoothly regardless of size. In practice the library sits on Reactor, and the README names Spring and Micronaut integration as a consequence of that choice.

The benefit is that subscribing to gateway.on(MessageCreateEvent.class) returns a stream you can compose without managing threads for each handler. The cost is the one visible in the quick example. Almost every call that returns data returns a Mono, so a straightforward imperative bot ends up with block() scattered through the handler, and each block occupies a thread while it waits.

This is the failure mode to check before adopting. A bot written by copying the quick example works, then degrades as message volume rises, because blocking calls on the event path consume threads that Reactor needs. The alternative style is to compose chains instead of blocking, which is idiomatic Reactor rather than idiomatic Java.

Other design points are smaller but worth knowing. The README positions the library as unopinionated, which in practice means it will not structure your application for you. JavaDoc is published per artifact on javadoc.io and referenced from the badge in the README header, so API detail lives there rather than in a hand written guide.

LGPL-3.0 is the one thing to read before shipping a bot

Discord4J is licensed LGPL-3.0, with the text in LICENSE.txt at the repository root. That is the decision most likely to affect an adoption and the least likely to be examined, because a bot that runs as a service is rarely distributed.

The distinction that matters is between distributing a modified library and merely running it. A hosted bot that depends on the library from Maven Central is using it remotely and is not in the position of a question most teams ask first. A desktop application or a product that bundles the jar is a different matter and needs the licence text read properly.

This is not legal advice and the point of mentioning it is narrow: LGPL was chosen deliberately rather than Apache 2.0, so a team whose policy is permissive-only will want to see the text rather than assume the norm.

The last push was on 2026-10-15, so the master branch is current. Sponsorship and the large bot examples in the README, including Groovy which served music to over four million servers before its shutdown in August 2021, describe reach rather than current maintenance.

Editorial conclusion

Discord4J suits JVM teams that already build with Reactor or Spring and want rate limiting and reconnection handled for them. Verify first that your application has the Message Content intent enabled in the developer portal, since the quick example silently receives empty message content without it, and note that the README's dependency snippets still pin 3.3.0 while the latest release listed is 3.3.3.

Frequently asked questions

How do I add Discord4J to a Gradle project?

Add the discord4j-core artifact from Maven Central. The README shows implementation 'com.discord4j:discord4j-core:3.3.0', with equivalent snippets for the Gradle Kotlin DSL, Maven and SBT.

Why is my Discord4J bot not responding to messages?

The README instructs you to make sure the Message Content intent is enabled in the developer portal. Without it the message content is empty and the comparison in the quick example never matches.

Which Discord Gateway version does Discord4J 3.3 support?

The version table lists v3.3.x as current on Gateway API v10, with mandatory non-privileged intents by default and fully supported interactions. v3.2.x targets v8 and v3.1.x is unsupported on v6.

Does Discord4J handle rate limiting and reconnection?

Yes. Automatic rate limiting, automatic reconnection strategies and consistent naming conventions are listed as benefits of building on the official Discord Bot API.

What licence is Discord4J released under?

LGPL-3.0, with the licence text in LICENSE.txt at the repository root. Check the terms yourself before bundling the library into a distributed product.

Official sources

  1. Discord4J/Discord4J on GitHub
  2. License: LGPL-3.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/discord4j-discord4j.svg)](https://hysenlabs.com/projects/discord4j-discord4j)

Was this useful?