Hot-load, unload, reload, and watch Bukkit plugins without restarting a Paper server.
- Load plugin jars from the server
plugins/directory. - Disable, unload, and reload plugins at runtime.
- Preserve dependency order and block dependent-plugin operations unless
--force(or-f) is supplied. - Watch plugin jars and debounce filesystem changes into reloads on the server thread.
- Inspect plugin metadata, command ownership, and loaded plugins.
- Use Paper's Brigadier command lifecycle so
/phris invisible to players without a PHR permission.
- Download
PaperHotReloader-<version>.jarfrom the latest release. - Place it in the server's
plugins/directory. - Start Paper once, then run
/phr helpfrom console or as an operator. - Grant the relevant
paperhotreloader.*permission nodes to server operators.
- Java 25
- Paper 26.2 or a compatible Bukkit/Paper fork
Use Java 25. HauntedPlatform is resolved from GitHub Packages; set PACKAGES_USER and PACKAGES_TOKEN (with read:packages) for a fresh local Maven cache. The committed .mvn/settings.xml reads these variables.
./mvnw -B -ntp verifyOutput jar: target/PaperHotReloader-<version>.jar
From clean main, run ./tools/release/update-version patch --pr to open a reviewed version PR. CI tests the PR; after merge, GitHub Actions publishes the Maven package, verifies that it resolves, and creates the tag and downloadable release jar with a SHA-256 checksum. See release tooling.
/phr reload— reload PaperHotReloader's configuration./phr restart [--force|-f]— reload PaperHotReloader itself./phr loadplugin <jarFiles...>— load and enable jars fromplugins/./phr unloadplugin <plugins...> [--force|-f]— disable and unload plugins./phr reloadplugin <plugins...> [--force|-f]— reload plugins./phr watchplugin <plugins...> [--force|-f]— reload watched jars when they change./phr unwatchplugin <plugin>— stop watching a plugin./phr plugininfo <plugin>— display plugin metadata./phr commandinfo <command>— display the owning plugin, when available./phr plugins [--version|-v]— list loaded plugins.
Bukkit does not expose plugin unloading as a public API. Unload uses a contained reflection bridge to remove a disabled plugin from Bukkit's registries, event handlers, scheduler, services, commands, and class loader. This is inherently dependent on server internals: test a plugin in staging before relying on hot reload in production, and prefer a full server restart after reloading plugins with static global state or native resources.