Links, support and visibility
/.modpacksch.json links the same project across CurseForge, Modrinth and GitHub,
adds donation links and server partners, and turns on GitHub Release downloads.
Made the thing everyone is downloading?
If CurseForge or Modrinth already links to your GitHub repo, drop in .modpacksch.json. Add downloads, support links and server partners from there.
You keep the files. Players get a page they can actually use.
Link your project
/.modpacksch.json to that repo.What you can change
Change the files whenever you like. There is no extra account or dashboard to keep up with.
/.modpacksch.json links the same project across CurseForge, Modrinth and GitHub,
adds donation links and server partners, and turns on GitHub Release downloads.
modpacksch-release.json names the playable asset, every supported game version
and loader, whether it belongs on the client or server, and only its direct dependencies.
Set "visibility": "hidden" and the page disappears from Modpacks.ch.
Prefer CurseForge, Modrinth or GitHub. Other verified exact sources stay one click away.
Changes normally show up within an hour.
No schema reading required
Fill in what you use. The valid JSON updates alongside you.
Already publishing with Gradle?
Keep using Mod Publish Plugin as normal. This plugin waits for CurseForge and Modrinth, sends your files to GitHub, then drops the Modpacks.ch JSON beside them. Multi-project build? That is fine too.
settings.gradle.kts
The Modpacks.ch plugin lives on CreeperHost Maven. Mod Publish Plugin comes from the Plugin Portal. Add both here once and you are done.
pluginManagement {
repositories {
maven { url = java.net.URI("https://maven.creeperhost.net") }
gradlePluginPortal()
}
}Kotlin DSL
Put the game version, install side and shared dependencies in defaults. If one JAR is different, point at its publish task and change just that one.
import net.creeperhost.modpacksch.EnvironmentSupport
plugins {
id("net.creeperhost.modpacksch") version "0.1.1"
}
modpacksCh {
defaults {
gameVersions.add("1.21.1")
environment {
client.set(EnvironmentSupport.REQUIRED)
server.set(EnvironmentSupport.OPTIONAL)
}
dependencies {
requiredCurseForge("306612")
optionalModrinth("P7dR8mSH")
}
}
publication(":fabric:publishGithub") {
displayName.set("Fabric 1.21.1")
loaders.add("fabric")
}
}Groovy DSL
We will not guess dependencies. Tell us which CurseForge, Modrinth or GitHub projects the file needs, can use or cannot run beside.
Still on 0.1.0? Pass null when you do not know an exact file or version. In 0.1.1,
you can just leave the second argument off.
import net.creeperhost.modpacksch.EnvironmentSupport
plugins {
id 'net.creeperhost.modpacksch' version '0.1.1'
}
modpacksCh {
defaults {
gameVersions.add('1.21.1')
environment {
client = EnvironmentSupport.REQUIRED
server = EnvironmentSupport.OPTIONAL
}
dependencies {
requiredCurseForge('306612')
optionalModrinth('P7dR8mSH')
}
}
publication(':fabric:publishGithub') {
displayName = 'Fabric 1.21.1'
loaders.add('fabric')
}
}Handled for you
Your main GitHub JAR or ZIP is playable automatically. Extra attachments stay as they
are unless you mark one with additionalPlayableFile(...).
The filename becomes the asset name. Loader details come from GitHub first, then matching CurseForge or Modrinth uploads. Those uploads can also supply the Minecraft version and install side.
A CurseForge file ID or Modrinth version ID is added only when SHA-256 proves it is the
exact same file and the project ID matches /.modpacksch.json.
If something does not add up, Gradle prints one useful warning and leaves the JSON off. Your normal release still goes out.
If a CurseForge or Modrinth upload fails, GitHub waits. A dry run still writes the JSON, just without IDs from uploads that never happened.
The .modpacksch.json file
Add your project IDs, switch on the repo’s GitHub Releases page and list Patreon, Ko-fi,
GitHub Sponsors, Open Collective or another support page you control. You can also hide the
Modpacks.ch page, choose the preferred download source or name the server hosts you actually
work with. Reorder the four main information sections with page.sections, and
explicitly hide any of them with page.disabled.
{
"$schema": "https://modpacks.ch/schemas/project-link-v1.json",
"version": 1,
"projects": {
"curseforge": "238222",
"modrinth": "P7dR8mSH",
"github": "example/example-mod"
},
"preferredDownload": "curseforge",
"destinations": [
{
"platform": "github",
"releases": true,
"manifestAsset": "modpacksch-release.json"
}
],
"hosting": [
{
"name": "Your server partner",
"url": "https://host.example/your-project"
}
],
"support": [
{ "platform": "patreon", "url": "https://www.patreon.com/example" },
{ "platform": "github-sponsors", "url": "https://github.com/sponsors/example" }
],
"page": {
"sections": [
"quick-answer",
"where-it-goes",
"before-you-install",
"about-project"
],
"disabled": []
},
"visibility": "listed"
}GitHub Releases
Add your JAR or ZIP and modpacksch-release.json to the same GitHub Release. Hit publish.
That’s it.
Don’t put a dot at the front. GitHub renames dot-prefixed release assets, so we can’t find the filename you asked us to use.
Tell us which game versions and loaders it supports, where it runs and what it needs. We’ll turn that into a normal download button and a dependency list players can follow.
Only add the mods your file directly needs. We’ll follow their dependency lists from there.
{
"$schema": "https://modpacks.ch/schemas/github-release-v1.json",
"version": 1,
"files": [
{
"name": "example-mod-1.21.1-4.2.0-fabric",
"asset": "example-mod-1.21.1-4.2.0-fabric.jar",
"providers": {
"curseforgeFile": "1234567",
"modrinthVersion": "AbC123xy"
},
"targets": {
"gameVersions": ["1.21.1"],
"loaders": ["fabric"]
},
"environment": {
"client": "required",
"server": "optional"
},
"dependencies": [
{
"provider": "curseforge",
"projectId": "306612",
"relation": "required"
},
{
"provider": "modrinth",
"projectId": "P7dR8mSH",
"relation": "required"
},
{
"provider": "github",
"projectId": "owner/library",
"relation": "optional"
}
]
}
]
}Quick reference
Keep the schema URL at the top and your editor can catch mistakes before you push.
projectsThe IDs that tie the config to the official page and linked GitHub repo. CurseForge uses its numeric project ID; Modrinth uses the project ID, not the slug.
destinationsTurns on GitHub Releases and names the modpacksch-release.json file.
preferredDownloadMakes CurseForge, Modrinth or GitHub the first exact release action when that destination is verified. Other available sources move into the download menu.
supportUp to eight Patreon, Ko-fi, GitHub Sponsors, Open Collective or custom support links.
hostingUp to four server partners you actually work with. Every host gets the same-sized spot.
page.sectionsOrders Quick answer, Where it goes, Before you install it and About this project. Keep all
four names in sections; add a name to disabled to hide it. Omit page to keep the standard layout with every section visible.
files[]Up to eight playable JAR or ZIP assets on one GitHub Release. Separate Fabric, NeoForge and other builds when their compatibility or dependencies differ.
targetsEvery game version and loader supported by that exact file.
providersConnects one GitHub artifact to its exact CurseForge file and Modrinth version so players can choose between verified copies of that release.
environmentSays whether the exact file is required, optional, unsupported or unknown on the client and dedicated server.
dependenciesUp to 32 direct required, optional or incompatible projects per file. Point at a project and only pin a file, version or GitHub asset when compatibility genuinely requires it.
Live for Minecraft: GitHub controls work for projects linked from CurseForge or Modrinth. Vintage Story and Hytale controls are coming later.
Non-plugin fallback
If the Gradle companion does not fit this build, save one as .github/workflows/publish-modpacksch.yml. Change the mod name, Minecraft
version, Java version and install side. Push a tag such as v4.2.0. That’s it.
One loader
For a normal Fabric project that puts its playable JAR in build/libs.
Runs ./gradlew build
One loader
For ModDevGradle and NeoGradle MDK projects that build into build/libs.
Runs ./gradlew build
Two loaders
For projects with fabric/ and neoforge/ subprojects.
Publishes both playable JARs
Two loaders
For common + Fabric + NeoForge MultiLoader projects.
Publishes both playable JARs
Single-loader files become <modname>-<mcver>-<modver>.jar.
Multi-loader files add -fabric or -neoforge, so nobody has to guess.
The release JSON can also list required, optional and incompatible dependencies.
Something not showing?
If something does not show up, it is usually one of these.
/.modpacksch.json on the default branch. Private repositories cannot be
read.manifestAsset, and every asset must be
a real JAR or ZIP on that same release.Give it a go
Apply the Gradle companion, add /.modpacksch.json and publish as normal. If the plugin
does not fit your build, the ready-made Actions workflows remain available.