A lightweight Java library for checking updates across multiple release platforms.
- Maven/JitPack ready
- Public GitHub API by default (free)
- Public Modrinth API by default (free)
- Hangar, Spigot legacy, CurseForge, and Maven metadata options
- Optional token support for private repos and higher rate limits
- Sync and async APIs
- Built-in chaining/fallback across multiple platforms
- Docs site (GitHub Pages):
https://ez-plugins.github.io/mc-plugin-update-notifier/ - Docs source:
docs/ - Start here:
docs/index.md
- Add JitPack repository:
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>- Add dependency:
<dependency>
<groupId>com.github.ez-plugins</groupId>
<artifactId>github-update-checker</artifactId>
<version>1.0.0</version>
</dependency>- Add GitHub Packages repository:
<repositories>
<repository>
<id>github</id>
<url>https://maven.pkg.github.com/ez-plugins/mc-plugin-update-notifier</url>
</repository>
</repositories>- Configure Maven credentials (
~/.m2/settings.xml):
<servers>
<server>
<id>github</id>
<username>${env.GITHUB_ACTOR}</username>
<password>${env.GITHUB_TOKEN}</password>
</server>
</servers>- Add dependency:
<dependency>
<groupId>com.github.ez-plugins</groupId>
<artifactId>github-update-checker</artifactId>
<version>1.0.0</version>
</dependency>import com.github.ezplugins.updater.UpdateChecker;
import com.github.ezplugins.updater.UpdateResult;
UpdateChecker checker = UpdateChecker.builder("PVP-Index", "pvpindex-factions", "1.2.3")
.build();
UpdateResult result = checker.checkNow();
if (result.hasError()) {
getLogger().warning("Update check failed: " + result.getError().orElseThrow().getMessage());
return;
}
if (result.isUpdateAvailable()) {
getLogger().info("Update available: " + result.getLatestTag().orElse("unknown"));
}UpdateChecker checker = UpdateChecker.builder("PVP-Index", "pvpindex-factions", "1.2.3")
.githubToken(System.getenv("GITHUB_TOKEN")) // optional
.build();
checker.checkNowAsync().thenAccept(result -> {
if (result.hasError()) {
getLogger().warning("Update check failed: " + result.getError().orElseThrow().getMessage());
return;
}
if (result.isUpdateAvailable()) {
getLogger().info("New version: " + result.getLatestVersion().orElse("unknown"));
getLogger().info("Release URL: " + result.getReleaseUrl().orElse("n/a"));
}
});import com.github.ezplugins.updater.ModrinthUpdateChecker;
ModrinthUpdateChecker checker = ModrinthUpdateChecker.builder("ezplugins-ezrtp", "1.2.3")
.loaders(java.util.List.of("paper"))
.gameVersions(java.util.List.of("1.21.4"))
.includeChangelog(false)
.userAgent("ez-plugins/ezrtp-update-checker/1.0 (https://github.com/ez-plugins/EzRTP)")
.build();
checker.checkNowAsync().thenAccept(result -> {
if (result.hasError()) {
getLogger().warning("Modrinth update check failed: " + result.getError().orElseThrow().getMessage());
return;
}
if (result.isUpdateAvailable()) {
getLogger().info("New Modrinth version: " + result.getLatestVersion().orElse("unknown"));
}
});import com.github.ezplugins.updater.HangarUpdateChecker;
HangarUpdateChecker checker = HangarUpdateChecker.builder("EZPlugins", "MyPlugin", "1.2.0")
.platform("PAPER")
.build();import com.github.ezplugins.updater.SpigotLegacyUpdateChecker;
SpigotLegacyUpdateChecker checker = SpigotLegacyUpdateChecker.builder(123456, "1.2.0")
.build();import com.github.ezplugins.updater.CurseForgeUpdateChecker;
CurseForgeUpdateChecker checker = CurseForgeUpdateChecker.builder(12345, "1.2.0")
.apiKey(System.getenv("CURSEFORGE_API_KEY"))
.build();import com.github.ezplugins.updater.MavenMetadataUpdateChecker;
MavenMetadataUpdateChecker checker = MavenMetadataUpdateChecker.builder(
"https://repo1.maven.org/maven2/com/example/my-lib/maven-metadata.xml",
"1.2.0"
).build();import com.github.ezplugins.updater.ChainedUpdateChecker;
import com.github.ezplugins.updater.ChainedUpdateResult;
UpdateChecker github = UpdateChecker.builder("PVP-Index", "pvpindex-factions", "1.2.3").build();
ModrinthUpdateChecker modrinth = ModrinthUpdateChecker.builder("pvpindex-factions", "1.2.3")
.loaders(java.util.List.of("paper"))
.gameVersions(java.util.List.of("1.21.4"))
.build();
ChainedUpdateResult chained = ChainedUpdateChecker.builder()
.primary(github)
.backup(modrinth)
.build()
.checkNow();
if (chained.getResult().hasError()) {
getLogger().warning("All update sources failed: " + chained.getFailuresBySource().keySet());
} else {
getLogger().info("Used source: " + chained.getSourceUsed().orElse("unknown"));
}- Latest release endpoint:
GET /repos/{owner}/{repo}/releases/latest - Unauthenticated requests are supported for public repositories.
- Optional token (
githubToken(...)) enables private repository checks and higher rate limits. - Version comparison uses semver when possible, then a fallback strategy for non-semver tags.
- Modrinth endpoint:
GET /project/{id|slug}/version(with optional filters). - Modrinth unauthenticated checks work for public projects; optional token (
authToken(...)) supports private access when available. - Modrinth requires a uniquely identifying
User-Agent; setuserAgent(...)to your project identity. - Hangar checker uses the versions API route and returns the newest listed version.
- Spigot checker uses
https://api.spigotmc.org/legacy/update.php?resource=<id>. - CurseForge checker reads project file data from the CurseForge API and supports
x-api-key. - Maven metadata checker reads
<latest>,<release>, or the newest<version>frommaven-metadata.xml.
- See CHANGELOG.md for release history.
- Tag releases with semver-like tags (for example
v1.2.0) for best comparison behavior. - GitHub Actions publishes to GitHub Packages on GitHub Release publication.
- JitPack compatibility is validated on version tags.
- GitHub Pages publishes documentation from
docs/via.github/workflows/docs-pages.yml.