Guidefor developers3 min read
Paper API Maven and Gradle coordinates
The repository, the artifact, the version string that trips people up, and why paperweight is a different decision from the plain API dependency.
The coordinates
Gradle, Kotlin DSL
repositories {
mavenCentral()
maven("https://repo.papermc.io/repository/maven-public/")
}
dependencies {
compileOnly("io.papermc.paper:paper-api:26.2-R0.1-SNAPSHOT")
}
Gradle, Groovy
repositories {
mavenCentral()
maven { url = 'https://repo.papermc.io/repository/maven-public/' }
}
dependencies {
compileOnly 'io.papermc.paper:paper-api:26.2-R0.1-SNAPSHOT'
}
Maven
<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>26.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
Substitute the Minecraft version you are targeting. Current versions with builds are listed on the Paper page, taken from PaperMC's own API.
Three details that catch people
The repository is required. The Paper API is not on Maven Central. Without
repo.papermc.io the dependency simply will not resolve, and the error does not point at the
missing repository as clearly as you would like.
-R0.1-SNAPSHOT is part of the version. It is the API generation for that Minecraft
version. It is a genuine snapshot that gets republished as the API changes within a version,
so your build will pick up updates. Do not try to pin it to a release version; there is not
one.
compileOnly, not implementation. The server provides the API at runtime. Bundling it
into your jar produces a jar tens of megabytes larger and class-loading conflicts with the
server's own copy. In Maven this is <scope>provided</scope>.
paper-api or paperweight
Two different tools for two different jobs, and picking the second by accident costs you a lot.
paper-api is the plugin API. Stable across a Minecraft version, documented, and what
almost every plugin should use. Fast builds, and a new Minecraft version is usually a version
bump and a recompile.
paperweight-userdev is a Gradle plugin that gives you access to the server's internal
implementation classes, remapped to readable names. You want it only when the API genuinely
cannot do what you need.
The cost is real:
- Slow first build. It downloads and remaps the server, which takes minutes.
- A rewrite every Minecraft version. Internals have no compatibility promise, which is the entire reason they are internals.
- Extra release steps, because the output has to be remapped for the server it runs on.
If you are not certain you need it, you do not. And if you do need it for one feature, put that feature behind your own interface so the version-specific part is one file rather than scattered through the project. See what breaks plugins on a new drop.
Java version
Match the Java version your target Minecraft release requires:
java {
toolchain.languageVersion = JavaLanguageVersion.of(25)
}
Compiling for a newer Java than the server runs produces UnsupportedClassVersionError at
load time, which is the same failure players hit with the game itself, one level down. The
Java version checker gives the requirement for any Minecraft version
from Mojang's own metadata.
Spigot and Bukkit coordinates
If you are targeting the older APIs instead:
// Spigot
compileOnly("org.spigotmc:spigot-api:26.2-R0.1-SNAPSHOT")
// Bukkit
compileOnly("org.bukkit:bukkit:26.2-R0.1-SNAPSHOT")
Both come from the Spigot repository at https://hub.spigotmc.org/nexus/content/repositories/snapshots/.
Paper's API is a superset of both, so a plugin compiled against Spigot runs on Paper. The
reverse is not true. Unless you specifically need to run on Spigot itself, compiling against
paper-api gives you more to work with and costs nothing.
Then set api-version
The dependency decides what you can compile against. plugin.yml's api-version decides how
the server treats your plugin at runtime, and they are separate choices. Set api-version to
the oldest version you actually support and have tested, not to the newest that exists. See
plugin.yml api-version values.