Quickstart Guide: Minecraft Plugin Development
How to code plugins for Bukkit, Spigot, Paper and Purpur, fast & easy (even if you've never coded before)
This guide is for people wanting to build unique Minecraft networks or simply get into Minecraft plugin development.
We’ll be writing our first plugin with event listener, creating exploding entities and having fun!
I wrote this article a bit longer than others because I want you to understand why things actually work, not just get a finished code to copy-paste.
Prefer a video tutorial? I made over 70 videos on plugin development:
Step 1: Install Java
Pick The Right Java Version
Summary: You need the right type, distribution and version of Java.
Type: To play Minecraft, you need Java Runtime Environment (JRE). To develop Minecraft plugins, you need JRE and Java Development Kit (JDK). The JDK includes a compiler to transform your code into a single jar file.
Distribution: Multiple companies build Java. We do not recommend Java from Oracle, because each version is free only for a limited time and then needs a paid license for commercial use, which is easy to miss. Instead, we will use Microsoft OpenJDK which is the officially tested JDK for Minecraft.
Version: See the table below:
| Server version | Recommended Java |
|---|---|
| 1.7.10 – 1.11 | Java 8 |
| 1.12 – 1.16.4 | Java 11 |
| 1.16.5 | Java 16 |
| 1.17 – 1.19 | Java 17 |
| 1.20 – 1.21.11 | Java 21 |
| 26.1+ | Java 25 |
Install Java JDK
Use the link below to download the right package for your operating system. For macOS the installation process is fully automatic.
Notice for Windows: We recommend selecting the “msi” package.
Get Java JDK here (see above which version you need):
https://learn.microsoft.com/en-us/java/openjdk/download

Step 2: Configure Your OS And Install Additional Software
Summary: You need to enable your operating system to show all file extensions to avoid issues. We also recommend getting a text editor with unicode support.
Step 1. Show all file extensions
To avoid hidden issues such as paperclip.jar.jar being shown as paperclip.jar later we need to setup your macOS/Windows to show file extensions.
Click here for a macOS guide (use All Files section) and click here for Windows guide on showing file extensions.
Step 2. Install a UTF-compatible text editor

When editing files for your Minecraft server or your plugins, such as .yml configs, you need an editor which saves plain text in UTF-8 so emojis and non-English letters survive. We recommend getting Notepad++ for Windows or Sublime Text for macOS or Linux.
Step 3: Install an IDE
Summary: You need a computer program to write your plugins code in. We recommend IntelliJ Community Edition.
An IDE stands for Integrated Development Environment, in short, it is a computer program that will help you write Java applications.
There are two most popular IDEs, IntelliJ and Eclipse. We will be using IntelliJ because it is considered to be the modern standard used by Google developers to write Android apps. It has a lot of inspections to help beginners write better code and is easy to navigate.
Get IntelliJ Community Edition from this link (scroll down to see the Community edition, which is free): https://www.jetbrains.com/idea/download/?section=windows
Step 4: Create Your Plugin Project
Summary: You need to create an empty Maven project in IntelliJ, tell Maven where to get the Paper API from and add a plugin.yml so the server can start your plugin.
Why Maven And Not Gradle
Paper’s own docs only show Gradle and mark Maven as discouraged. We disagree, at least for beginners. A Gradle project starts with six files and a build script written in Kotlin, so a typo gives you a Kotlin compiler error instead of a plain message, and Gradle also keeps a daemon running in the background whose version has to match the plugins you use. A Maven project is one file, pom.xml, plain XML you can read top to bottom which IntelliJ understands without any extra setup. The Paper API works the same with both so you lose nothing, and if you ever need Gradle for a bigger project later, you can switch in an afternoon.
We also skip the Minecraft Development plugin for IntelliJ since it generates the same files you are about to write by hand, and writing them yourself is the only way to learn what they actually do.
Create The Project In IntelliJ
Open IntelliJ and click New Project on the welcome screen (or File > New > Project if you already have another project opened).

Fill in the wizard:
- Name: explodingcows. This becomes the folder name and the artifactId.
- Location: a folder on your local disk. Do NOT use OneDrive or Google Drive to store Minecraft plugin source code because cloud storages cause issues with cache files IntelliJ creates.
- Language: Java.
- Build system: Maven.
- JDK: the Java 25 you installed in Step 1. If the list is empty, click it, select Add JDK from disk and pick the folder where Java got installed.
- Add sample code: untick it.
- Advanced Settings: GroupId is your reversed domain name. If you own mineacademy.org, put org.mineacademy, if your gmail is [email protected], put com.gmail.john1995 and if you have neither, just put me.yourname. Make sure it’s all lower case without spaces and letters or numbers only. ArtifactId stays explodingcows.
Click Create. IntelliJ makes the src/main/java and src/main/resources folders and a pom.xml. The pom.xml gives instructions to Maven, the build system that compiles your code and puts all of your plugin’s files together into a single .jar file. Open pom.xml and replace everything inside with this:
4.0.0
org.mineacademy
explodingcows
1.0.0
25
UTF-8
papermc
https://repo.papermc.io/repository/maven-public/
io.papermc.paper
paper-api
[26.2.build,26.3)
provided
Every key has a job:
- groupId, artifactId, version: the identity of your plugin. We recommend starting the version at 1.0.0 and working up to 1.0.9 and then 1.1.0 and so on. Change this on each of your plugin’s public release.
- maven.compiler.release: the Java version your code compiles for. Minecraft 26.1 and newer need Java 25. Please note that a plugin compiled on Java 25 will not load on anything older, so if you target an older server, use the Java version from the table in Step 1.
- repositories: where Maven downloads the Paper API from, since Maven Central does not host it.
- dependencies: the Paper API itself. The version [26.2.build,26.3) means the newest 26.2 build, and the provided scope tells Maven the server already ships this library so it must not be copied into your jar.
Keep the upper bound in that version. An open range like [26.2.build,) which Paper’s own setup page shows has no upper limit, so Maven also takes pre-releases of the next Minecraft version. We tested it in September 2026 and it pulled 26.3-pre-2 into a project meant for 26.2, which compiles fine and then fails on the running server. If you want the build frozen completely, write one exact version such as 26.2.build.121-stable instead of a range.
Targeting an older server? Versions before 26.1 use the old format, for example 1.21.11-R0.1-SNAPSHOT for Minecraft 1.21.11.
After you paste the file, click the small Maven icon that appears in the top right corner of the editor (or press Ctrl+Shift+O, on macOS Shift+Cmd+I) to download the Paper API. You only need to do this again whenever you change pom.xml.
Add The plugin.yml
Maven reads pom.xml, the server reads plugin.yml. Right click the src/main/resources folder, click New > File, name it plugin.yml and paste this in:
name: ExplodingCows
version: 1.0.0
main: org.mineacademy.explodingcows.ExplodingCows
api-version: '26.2'
author: YourName
description: Right click a cow to make it explode.
- name: shown in /plugins and in the console. Letters, numbers and underscores only.
- version: keep it the same as in pom.xml.
- main: the full name of the class we write in the next step, package plus class name. A typo here stops the plugin from loading.
- api-version: the Paper API version your plugin is written for. A server older than this refuses to load your plugin with “Unsupported API version”, a newer one still loads it. If you leave it out, the server treats your plugin as a legacy plugin from before 1.13 and warns about it. Keep the quotes.
- author and description: shown by /version ExplodingCows in game, so put your own name there.
You can see all available options for plugin.yml here.
Step 5: Write Your Plugin
Right click the src/main/java folder, click New > Package and name it org.mineacademy.explodingcows (your groupId, a dot and your artifactId). Then right click the new package, click New > Java Class, name it ExplodingCows and replace the generated file with this:
package org.mineacademy.explodingcows;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.plugin.java.JavaPlugin;
public final class ExplodingCows extends JavaPlugin implements Listener {
@Override
public void onEnable() {
this.getServer().getPluginManager().registerEvents(this, this);
}
@EventHandler(ignoreCancelled = true)
public void onRightClick(PlayerInteractEntityEvent event) {
Entity entity = event.getRightClicked();
if (entity.getType() == EntityType.COW)
entity.getWorld().createExplosion(entity.getLocation(), 5);
}
}
If IntelliJ underlines the imports in red, click the Maven icon from Step 4 to download the Paper API.
Your Plugin’s Structure
- pom.xml: instructions for Maven, the build system that puts all project files together into a single plugin .jar.
- src/main/java: Java code for your plugin. Each subfolder is one part of a class’ package.
- ExplodingCows: the main class the server starts when it loads your plugin.
- src/main/resources: files that are not Java code, such as your config. They are included in the plugin’s jar.
- plugin.yml: instructions for the server on how to start your plugin.
Breakdown Of The Main Plugin’s Class
Let’s break down the code in your main plugin’s class, line by line.
Don’t worry if that seems too complicated for you now, I’ll share how you can learn the Java programming language in its complete form below and it’s easier than it looks 😉
Package declaration
package org.mineacademy.explodingcows;
Every class in Java starts with a package declaration. This must be exactly the same as the folders structure we discussed above.
To rename your main plugin’s class or move it to a different package, simply right click the package or the class name on the left panel in IntelliJ under Project, then click Refactor and select Rename.
IntelliJ will remove the old folders, make the new ones and move all classes there automatically.
Imports
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.plugin.java.JavaPlugin;
Every time you use another class which is in a different package you must import it using the import statement. IntelliJ can manage imports automatically and you can enable Optimize Imports On The Fly option in its settings.
We have access to classes in the org.bukkit package because we are importing Paper API (or Spigot if you so desire) in pom.xml.
IntelliJ reads the file and downloads the API jar in the background to a hidden .m2 folder inside your Users folder. The jar is then made available to your project. The same API is also available on the server.
The class declaration
public final class ExplodingCows extends JavaPlugin implements Listener {
The “public” is an access modifier which means code outside of your package, such as the server, can use the class. Keep it public like every plugin does.
The “final” keyword means nobody can extend the class (because there’s no purpose to it, only by accident) and the “extends JavaPlugin” means we ourselves are extending JavaPlugin class.
By extending a class we mean that we share the fields and methods from JavaPlugin class. That way, Bukkit API can properly find and launch our plugin.
The “implements Listener” means our class implements the interface “Listener”. An interface is a list of methods a class promises to have, this one is empty and only marks the class so Bukkit can register it for events. Bukkit only looks for event methods in classes that implement a Listener and that you registered with it, which we do in onEnable() below. We’ll talk about that later.
The onEnable() method
@Override
public void onEnable() {
this.getServer().getPluginManager().registerEvents(this, this);
}
The “@Override” is an annotation which means there is already a method (a function) by the same name in the class we are overriding, JavaPlugin. We are overriding this method to add custom behavior to the plugin when the server starts or is reloaded.
The “public” is an access modifier as explained above, the “void” means that the method does not return any result, the “onEnable” is the name of the method (if it would be anything else, than @Override could not be used and it would not get called automatically), the () brackets mark that this is a method, and are empty because the method does not take in any arguments (data), and then there’s an opening { bracket and } at the end of the method.
Let’s break down the line “this.getServer()…”:
The “this” means we are reading methods or fields in this instance of our class. The server automatically makes a new instance of your plugin when it is loaded.
In our class (“this class”), we call getServer() which is a method found in JavaPlugin that returns the Minecraft server class. In this class, we call getPluginManager() which returns a plugin manager class and inside of that class we finally call the method registerEvents().
This method registers events and takes two parameters, first the class which implements Listener, then the plugin that owns it. Both of them are “this” here because our own class does both jobs. When you later move your listeners into their own classes, the first argument becomes that class and the second one stays “this”.
Similarly to onEnable(), Bukkit automatically calls the method onDisable() whenever your plugin is disabled by the server stopping or being reloaded.
The onRightClick() method – making entities explode on right click
@EventHandler(ignoreCancelled = true)
public void onRightClick(PlayerInteractEntityEvent event) {
Entity entity = event.getRightClicked();
if (entity.getType() == EntityType.COW)
entity.getWorld().createExplosion(entity.getLocation(), 5);
}
Because your main class implements a listener and we registered events in it, we can make special methods that Bukkit will find automatically and call whenever the event described in the method is fired.
To do this, we need to preface the method with @EventHandler annotation that will let Bukkit identify that this is an event method. The ignoreCancelled = true part tells Bukkit to skip your method when another plugin, such as a land protection plugin, has already cancelled the interaction. The method needs to be public and a void. Inside its arguments, place exactly one argument, which is one of the hundreds of available plugin events depending on whether you are using Spigot, Paper or Purpur API.
Inside our example method, we listen for PlayerInteractEntityEvent which is fired on right click on any entity. In the method body, we first declare a variable Entity and save the right clicked entity to it. We then check if the entity type equals to a cow and create an explosion at the entity’s location with the power of 5. TNT has the power of 4, so this is a little stronger, and just like TNT it breaks the blocks around the cow. Try it on a test world, not on a map you care about.
I encourage you to change the entity type and the explosion power and get some fun results out of this!
Step 6: Build Your Plugin Into A JAR
Open the Maven tool window from the m icon on the right edge of IntelliJ, expand Lifecycle and double click package. A new bottom window should open with the console printing Maven compile messages. In most instances, you can ignore all Maven warnings as long it says BUILD SUCCESS at the bottom. If it fails, read the first red line, it names the file and the line with the mistake.
After a successful build, a new folder “target” will appear in your plugin’s source folder. You’ll find your plugin jar ready to be installed there, named explodingcows-1.0.0.jar.
Step 7: Test Your Plugin On A Server
If you do not have a Minecraft server, we recommend installing one to your computer. It’s free, and there is no delay in connection to it so you can test your plugins the fastest, and save time.
Click here to learn how to create a local Minecraft server on your computer.
Place the plugin jar into your plugins/ folder and start your server.
In the game, type /plugins. As long as ExplodingCows shows up in green, it’s loaded. You can also check your console startup log for any errors related to your plugin loading.
We can now test the exploding cows functionality by spawning a cow and right clicking it:

And just like that, we’ve made your first Minecraft plugin!
What a journey, congratulations! Want to do more cool stuff with your plugin? Keep reading…
Step 8: Add A Command
Let’s add a /explode <player> command using the Bukkit command API, which every server type supports. It checks the permission, finds the player, explodes him and tab completes online player names. First, the server needs to know the command exists, so add this block to the bottom of your plugin.yml:
commands:
explode:
description: Explode a player.
usage: /
permission: explodingcows.explode
Then right click your package, click New > Java Class, name it ExplodeCommand and paste this in:
package org.mineacademy.explodingcows;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
public final class ExplodeCommand implements CommandExecutor, TabCompleter {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!sender.hasPermission("explodingcows.explode")) {
sender.sendMessage("You do not have permission to use this command.");
return true;
}
if (args.length != 1) {
sender.sendMessage("Usage: /" + label + " ");
return true;
}
Player target = Bukkit.getPlayerExact(args[0]);
if (target == null) {
sender.sendMessage("Player " + args[0] + " is not online.");
return true;
}
target.getWorld().createExplosion(target.getLocation(), 5);
sender.sendMessage("Exploded " + target.getName() + ".");
return true;
}
@Override
public List onTabComplete(CommandSender sender, Command command, String label, String[] args) {
if (args.length != 1)
return List.of();
return Bukkit.getOnlinePlayers().stream().map(Player::getName).filter(name -> name.toLowerCase().startsWith(args[0].toLowerCase())).toList();
}
}
Finally, add these lines to onEnable() in your main class so the server knows which class runs the command:
ExplodeCommand command = new ExplodeCommand();
this.getCommand("explode").setExecutor(command);
this.getCommand("explode").setTabCompleter(command);
The name in getCommand() must match the one in plugin.yml, otherwise getCommand() returns null and the plugin fails to enable.
Build the jar again like in Step 6, put it on your server and try /explode with a player’s name. I encourage you to play with the messages and the explosion power before moving on!
From here, the Paper docs pick up where this guide stops: Brigadier commands (the newer command system), configuration files, the scheduler and persistent data.
Step 9: Actually Learn Java + Plugin Development
You need to learn the Java programming language and the Bukkit/Spigot/Paper API for you to understand how to make the features you want in your plugins.
Learning Java from tutorials is slow, because they focus on topics we don’t need in plugins. AI can help, but it still mixes up API versions and hallucinates out code. YouTube tutorials are painfully disorganized, outdated and can teach bad practices. Even learning from the official Paper docs means you’re completely on your own, nobody will be actually reviewing your code.
That’s why I built Project Orion. It’s a complete video-course with 6 weeks of training and weekly live coaching calls with myself personally on Zoom.
Over 4,000 students have come through the training. It bundles a full Java course with the plugin material, 177 plugin development lessons.
You will learn game events and commands, GUI menus, SQL databases, BungeeCord/Velocity, custom mobs, claims and regions, minigames, anti-lag and obfuscation.