What is a Minecraft plugin?
A Minecraft plugin is a JAR file you drop into the plugins/ folder of a Paper, Spigot, or Bukkit server. When the server starts, it loads the plugin and the plugin can listen for game events, register custom commands, modify gameplay mechanics, store data, interact with other plugins, and much more — all without touching Minecraft's own source code.
Plugins differ from mods (Fabric, Forge, NeoForge) in one crucial way: they run entirely server-side. Players don't need to install anything. This makes plugins the go-to approach for custom server features, economy systems, minigames, and moderation tools.
The standard software stack in 2026:
- Paper — the most widely used server JAR, extends Spigot with performance patches and a richer API
- Spigot — still widely used, Paper is backwards-compatible with Spigot plugins
- Folia — Paper's multi-threaded fork for very high player counts
- Velocity — the modern proxy server (like BungeeCord but faster); uses its own API
This guide targets Paper, which has the best API, the largest community, and is what most modern plugins are written for.
Prerequisites and tools
You need three things before writing a single line of plugin code:
1. Java 21
Minecraft 1.21+ requires Java 21. Download the JDK (not just the JRE) from Adoptium or Oracle. After installing, confirm with:
java -version
javac -version
Both should report 21.x.x.
2. Apache Maven
Maven manages your dependencies (including the Paper API JAR) and handles compilation. Download Maven, extract it, and add its bin/ folder to your system PATH. Confirm:
mvn -version
3. An IDE
IntelliJ IDEA (Community edition is free) is strongly recommended — it has first-class Maven support and a Java debugger. VS Code with the Java extension pack also works.
💡 Want to skip all of this? If you don't want to manage a Java development environment, StackNest generates, compiles, and delivers a ready-to-use plugin JAR from a plain-English description — no local toolchain needed. Jump to the AI shortcut section.
Setting up a Maven project
Create a new directory for your plugin and add a pom.xml at the root. Here's a minimal template for a Paper 1.21.4 plugin:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-plugin</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<java.version>21</java.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
</properties>
<repositories>
<repository>
<id>papermc</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.21.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
The provided scope tells Maven to use the Paper API for compilation but not bundle it into your JAR (the server already has it). The maven-shade-plugin bundles any third-party libraries you add.
Writing your main plugin class
Create the source file at src/main/java/com/example/MyPlugin.java:
package com.example;
import org.bukkit.plugin.java.JavaPlugin;
public final class MyPlugin extends JavaPlugin {
@Override
public void onEnable() {
getLogger().info("MyPlugin has been enabled!");
// Register commands and listeners here
}
@Override
public void onDisable() {
getLogger().info("MyPlugin has been disabled.");
}
}
Every plugin has exactly one class that extends JavaPlugin. The onEnable() method runs when the server loads the plugin, and onDisable() runs when the server shuts down or the plugin is reloaded.
The plugin.yml file
Create src/main/resources/plugin.yml. This file tells the server the plugin's name, version, main class, and what API version it targets:
name: MyPlugin
version: "1.0.0"
main: com.example.MyPlugin
api-version: "1.21"
description: My first Minecraft plugin
authors: [YourName]
commands:
hello:
description: Say hello
usage: /hello
The api-version field is required on Paper 1.20.5+. Omitting it causes a deprecation warning; using an incorrect value can prevent the plugin from loading.
Registering commands
Commands are handled by a CommandExecutor. Create src/main/java/com/example/HelloCommand.java:
package com.example;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public class HelloCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender,
@NotNull Command command,
@NotNull String label,
@NotNull String[] args) {
sender.sendMessage(
Component.text("Hello from MyPlugin!", NamedTextColor.GREEN)
);
return true;
}
}
Then register it in your main class inside onEnable():
Objects.requireNonNull(getCommand("hello"))
.setExecutor(new HelloCommand());
📌 Paper uses the Adventure text component library for all player-facing messages. The old ChatColor / §-prefix approach still works but is deprecated. Use Component.text() for any new plugin.
Handling events
Event listeners let your plugin react to game events — a player joining, breaking a block, dying, and hundreds more. Create src/main/java/com/example/PlayerListener.java:
package com.example;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
public class PlayerListener implements Listener {
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
event.getPlayer().sendMessage(
Component.text("Welcome to the server!", NamedTextColor.GOLD)
);
}
}
Register it in onEnable():
getServer().getPluginManager()
.registerEvents(new PlayerListener(), this);
The full list of available events is in the Paper Javadoc. Every class in the org.bukkit.event.* and io.papermc.paper.event.* packages can be listened to.
Event priorities
By default, @EventHandler runs at NORMAL priority. Use @EventHandler(priority = EventPriority.HIGH) if you need to run after other plugins, or LOWEST if you want to run first. Use ignoreCancelled = true to skip events already cancelled by another plugin:
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onBlockBreak(BlockBreakEvent event) {
// ...
}
Compiling and testing
From your project root, run:
mvn clean package
If the build succeeds, your JAR will be in target/my-plugin-1.0.0.jar (or target/my-plugin-1.0.0-shaded.jar if you're using the shade plugin). Copy it to your test server's plugins/ folder and start or reload the server.
To reload without a full server restart (development only — not recommended for production):
/reload confirm
Common first-time errors
- "Cannot find symbol" — you're importing a class you haven't declared. Check all imported types exist in your code or in the Paper API.
- "Plugin.yml is missing required field 'main'" — your plugin.yml references the wrong class path. Match it exactly to your package.ClassName.
- "Could not load plugin" — API version mismatch or a missing dependency. Check the server console for the full error.
- Plugin loads but commands don't work — command not declared in plugin.yml, or the executor wasn't registered in onEnable().
The AI shortcut: skip the boilerplate entirely
Everything above describes the traditional workflow. It requires a working Java development environment, familiarity with Maven, and understanding of the Paper API. For many server owners, that's a significant barrier — especially for one-off plugins or experimental features.
StackNest is an AI-powered Minecraft plugin generator that handles all of this automatically:
- Describe your plugin in plain English: "A kit plugin with Warrior, Archer, and Mage kits. 5-minute cooldown per kit. Kits are listed in a chest GUI. Warrior gets a diamond sword and iron armour. Mage gets a blaze rod that fires fireballs on right-click."
- StackNest's AI generates the full plugin — main class, all supporting classes, plugin.yml, pom.xml
- It compiles the code server-side and runs up to 5 auto-fix passes if there are errors
- You download the compiled JAR and drop it straight into your plugins/ folder
✅ The free tier includes 3 plugin generations per month — no credit card required. Complex plugins with GUIs, economy integration, and multi-class structures are supported on all paid plans from £4/month.
For most moderately complex plugin requests, StackNest produces a working plugin in under 60 seconds. For server owners who aren't Java developers, it removes the development environment requirement entirely.
For developers, it's most useful for the boilerplate-heavy parts: GUI structures, data storage patterns, scheduler tasks, and event wiring. The AI for Java developers guide covers the workflow in more detail.
Frequently asked questions
What language do Minecraft plugins use?
Paper, Spigot, and Bukkit plugins are written in Java. Kotlin is also supported and growing in popularity — it compiles to the same JVM bytecode and works transparently with the Paper API. Velocity proxy plugins also use Java or Kotlin.
Do I need to know Java to make a Minecraft plugin?
Traditionally yes. However, AI tools like StackNest let you describe what you want in plain English and receive a compiled, working plugin JAR — no Java knowledge required. If you're learning Java, building plugins is one of the most engaging ways to do it; our guide for CS students covers that angle.
What is the Paper API?
The Paper API is the modern standard for Minecraft plugin development. It extends Bukkit/Spigot with performance improvements, async chunk loading, the Adventure text library, custom mob goals (Pathfinder Goals), and Paper-specific events. The Paper API is a superset of the Spigot API — plugins written for Spigot run on Paper, but Paper-specific features won't work on Spigot-only servers.
How long does it take to make a Minecraft plugin?
A simple command plugin takes an experienced Java developer 30–60 minutes including project setup. A full plugin with persistent data storage, economy integration, and a chest GUI takes days. With StackNest, even complex plugins with GUIs and multi-class structures are generated and compiled in under a minute.
Can I make a Minecraft plugin without an IDE?
Technically yes — Maven can be run from the terminal and you can edit Java files in any text editor. In practice, an IDE like IntelliJ IDEA makes the process significantly easier: autocomplete, inline API docs, refactoring, and integrated compilation save hours on any non-trivial plugin.
Spigot vs PaperMC — which API should I target?
Target Paper. The Paper API is a superset of Spigot, so your plugin will still run on Spigot servers; and Paper gives you access to better events, improved performance, the Adventure library, and a more active development team. Most servers have already migrated to Paper or a fork like Folia or Purpur.
Don't want to set up a Java environment?
StackNest generates, compiles, and delivers a working plugin JAR from a plain-English description. Free to start.
Generate a plugin free →