Overview
FeatherMC is a fork of Paper. It does not publish its own API artifact. Its changes are inside the server: defaults, guards and internal work. The plugin-facing API is Paper's, unchanged.
- Compile against
io.papermc.paper:paper-apifor 26.3. - Target Java 25.
- Test on Paper or FeatherMC. Behaviour your plugin can observe through the API is the same.
Because the API is Paper's, Paper's developer docs apply word for word. This page only documents what is specific to FeatherMC.
Project setup
Add Paper's Maven repository and the paper-api dependency, exactly as you would for Paper.
repositories { maven { url = uri("https://repo.papermc.io/repository/maven-public/") } } dependencies { compileOnly("io.papermc.paper:paper-api:26.3.build.+") } java { toolchain.languageVersion.set(JavaLanguageVersion.of(25)) }
repositories { maven { url = 'https://repo.papermc.io/repository/maven-public/' } } dependencies { compileOnly 'io.papermc.paper:paper-api:26.3.build.+' } java { toolchain.languageVersion = JavaLanguageVersion.of(25) }
<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.3.build,)</version> <scope>provided</scope> </dependency> </dependencies>
Plugin descriptor
Use plugin.yml or paper-plugin.yml with the same fields and api-version you would use for Paper 26.3. FeatherMC loads both formats through Paper's own plugin loader, so nothing in your descriptor needs to mention FeatherMC.
If your plugin declares that it depends on Paper, that check passes on FeatherMC, because the server keeps Paper's brand ID.
Detecting FeatherMC
Most plugins never need to know. If you want to show it in a debug command or enable something only on FeatherMC, check the brand name. The brand ID is deliberately still Paper's.
import io.papermc.paper.ServerBuildInfo; public static boolean isFeatherMC() { return "FeatherMC".equals(ServerBuildInfo.buildInfo().brandName()); } // Bukkit.getName() -> "FeatherMC" // ServerBuildInfo.buildInfo().brandId() -> papermc:paper
Don't use this to work around Paper behaviour. If something behaves differently on FeatherMC than on Paper in a way your plugin can see, that is a FeatherMC bug and worth reporting.
Compatibility contract
FeatherMC keeps these the same as Paper on purpose, so tools and plugins built for Paper keep working:
| Surface | On FeatherMC |
|---|---|
| Java packages | io.papermc.paper, org.bukkit, com.destroystokyo.paper |
| Brand ID | papermc:paper |
| Brand name | FeatherMC |
| Persistent data / NBT keys | Paper's keys, unchanged |
| Config files | config/paper-global.yml, config/paper-world-defaults.yml, per-world paper-world.yml |
| Commands and CLI flags | /paper and Paper's startup flags |
What players can observe is also held constant. Redstone timing, mob behaviour, drops, physics and world generation must match Paper. The only exceptions are the opt-in guards documented below, and they are off unless an admin turns them on.
Config reference: feather.yml
FeatherMC's own options live in feather.yml in the server root, separate from Paper's config/ folder. The file is created with every option and its comment on first start. It is read once at startup, so restart to apply changes.
mass-destruction
Guards against mass-TNT "orbital strike" detonations.
| Key | Type | Default | Description |
|---|---|---|---|
prevent-tnt-mass-detonation | boolean | false | When true, a dense cluster of primed TNT is deleted just before it explodes instead of detonating. Only TNT inside the radius is removed. |
threshold | int | 100 | How many primed TNT within the radius counts as a mass detonation. |
radius | double | 8.0 | Radius in blocks checked around a TNT that is about to explode. |
mass-destruction: prevent-tnt-mass-detonation: false threshold: 100 radius: 8.0
Changed Paper defaults
FeatherMC changes a small number of Paper's defaults. They only apply to keys that are not already in your config, so a server migrated from Paper keeps its existing values until you change them.
| Key in paper-world-defaults.yml | Paper | FeatherMC |
|---|---|---|
entities.behavior.inactive-mob-goal-selector-throttle-rate | disabled | 20 |
chunks.entity-per-chunk-save-limit.arrow | -1 | 16 |
chunks.entity-per-chunk-save-limit.ender_pearl | -1 | 16 |
chunks.entity-per-chunk-save-limit.experience_orb | -1 | 16 |
chunks.entity-per-chunk-save-limit.fireball | -1 | 16 |
chunks.entity-per-chunk-save-limit.small_fireball | -1 | 16 |
chunks.entity-per-chunk-save-limit.snowball | -1 | 16 |
See the features page for why each default was chosen and when to change it.
Javadocs
There is no separate FeatherMC Javadoc, because there is no separate API. Use Paper's:
Found an API difference between Paper and FeatherMC? Open an issue on the FeatherMC repository with a small plugin that shows it.