Java servers run a jar. There is no build step on the server: you build the bot on your computer (or in GitHub Actions) into one jar that includes its dependencies, and the server runs java -jar on it.
Versions
Java 17, 21 and 25, chosen at checkout or under Startup, Docker Image. Java 21 is the default. Pick at least the version your jar was built for; newer is fine.
Build a runnable jar
A normal jar task leaves JDA and your other libraries out, and the bot stops with NoClassDefFoundError. Build a jar with dependencies included:
Gradle
plugins {
id 'java'
id 'application'
id 'com.gradleup.shadow' version '8.3.5'
}
application {
mainClass = 'com.example.bot.Main'
}
Then ./gradlew shadowJar, and upload build/libs/yourbot-1.0-all.jar.
Maven
Add the maven-assembly-plugin with the jar-with-dependencies descriptor and your main class in its manifest, run mvn package, and upload target/yourbot-1.0-jar-with-dependencies.jar.
Upload and run it
- Upload the jar in Files, or over SFTP.
- Leave Bot file empty if it is the only jar: it is found in the top folder,
build/libsortarget. With several, set it to the right one. - Restart. The console shows
Starting: java -jar yourbot-1.0-all.jar, then your bot's output.
Git deploy pulls files but does not build Java. To deploy from GitHub, have a GitHub Actions workflow build the jar and commit it to a branch the server follows, or upload the jar by hand.
The token
String token = System.getenv("BOT_TOKEN");
JDA jda = JDABuilder.createDefault(token).build();
Some ready-made bots ask for their token in the console instead (JMusicBot does on its first start). Type it into the box at the bottom of the Console page; what you type there goes to the program's input.
Memory
The heap may use three quarters of your plan's memory (768 MB on Flurry); on its own, Java would only take a quarter. If the bot stops with java.lang.OutOfMemoryError, something is holding on to too much, or the bot needs a bigger plan. JDA's member and message caches are the usual suspects: turn off the cache flags and intents you do not use.
Stopping cleanly
Stop sends the program an interrupt, which runs Java's shutdown hooks. To let JDA close its connection to Discord properly, add one:
Runtime.getRuntime().addShutdownHook(new Thread(jda::shutdown));
When the jar will not start
UnsupportedClassVersionError ... compiled by a more recent version: pick a newer Java under Startup.no main manifest attribute: the jar does not say which class to start. SetmainClassas above and rebuild.NoClassDefFoundError: net/dv8tion/jda/...: the jar was built without its dependencies. UseshadowJarorjar-with-dependencies.InvalidTokenException: the token is wrong orBOT_TOKENis empty. Paste it into Startup and restart.
The console adds a [SnowServers] Hint: line for each of these.
Something here wrong or out of date? Tell us and it gets fixed.