Made the thing everyone is downloading?

No new account. Just your repo.

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

  1. Link your GitHub repo from CurseForge or Modrinth.
  2. Add /.modpacksch.json to that repo.
  3. Push it. Your links and settings will appear here automatically.
  4. Want downloads here too? Apply the Gradle companion, or add the release file shown below to your GitHub Release.

What you can change

Your page, without another dashboard.

Change the files whenever you like. There is no extra account or dashboard to keep up with.

Project page

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.

Each release

Files, loaders and dependencies

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.

Page removal

Hide your page

Set "visibility": "hidden" and the page disappears from Modpacks.ch.

Your existing pages

Choose where downloads start

Prefer CurseForge, Modrinth or GitHub. Other verified exact sources stay one click away.

Changes normally show up within an hour.

No schema reading required

Build your project file

Fill in what you use. The valid JSON updates alongside you.

1. Where your project lives

Add at least one. These are IDs, not display names.

2. Downloads
3. Project page

Reorder the tiles. Turning one off writes an explicit disable.

4. Support links

Optional. Patreon, Ko-fi, sponsors or another page you control.

5. Server partners

Optional. Add only hosts you actually work with.

Already publishing with Gradle?

One release. One extra file. No second workflow.

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

Tell Gradle where the plugin lives.

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

Set the shared bits once.

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

Prefer Groovy? Same job.

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

What the plugin can work out

  • Main release file

    Your main GitHub JAR or ZIP is playable automatically. Extra attachments stay as they are unless you mark one with additionalPlayableFile(...).

  • Name and game details

    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.

  • Marketplace IDs

    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.

  • Safe fallback

    If something does not add up, Gradle prints one useful warning and leaves the JSON off. Your normal release still goes out.

  • Upload order

    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

One hidden file. Deliberately boring.

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

Ship the file. We’ll handle the fiddly bits.

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

What each bit does.

Keep the schema URL at the top and your editor can catch mistakes before you push.

projects

The 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.

destinations

Turns on GitHub Releases and names the modpacksch-release.json file.

preferredDownload

Makes CurseForge, Modrinth or GitHub the first exact release action when that destination is verified. Other available sources move into the download menu.

support

Up to eight Patreon, Ko-fi, GitHub Sponsors, Open Collective or custom support links.

hosting

Up to four server partners you actually work with. Every host gets the same-sized spot.

page.sections

Orders 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.

targets

Every game version and loader supported by that exact file.

providers

Connects one GitHub artifact to its exact CurseForge file and Modrinth version so players can choose between verified copies of that release.

environment

Says whether the exact file is required, optional, unsupported or unknown on the client and dedicated server.

dependencies

Up 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

Or copy a GitHub Actions workflow.

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

Fabric Loom

For a normal Fabric project that puts its playable JAR in build/libs.

Runs ./gradlew build

Download .yml

One loader

NeoForge

For ModDevGradle and NeoGradle MDK projects that build into build/libs.

Runs ./gradlew build

Download .yml

Two loaders

Architectury

For projects with fabric/ and neoforge/ subprojects.

Publishes both playable JARs

Download .yml

Two loaders

MultiLoader Template

For common + Fabric + NeoForge MultiLoader projects.

Publishes both playable JARs

Download .yml

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?

Check the boring stuff first.

If something does not show up, it is usually one of these.

  1. The repo is not linked from CurseForge or Modrinth. Add the public GitHub repository to the project’s CurseForge or Modrinth source link first.
  2. The file is not at the repo root. It must be /.modpacksch.json on the default branch. Private repositories cannot be read.
  3. The project ID does not match. Use the numeric CurseForge project ID or Modrinth project ID. A display name or slug is not enough.
  4. The manifest and asset names differ. The JSON filename must match manifestAsset, and every asset must be a real JAR or ZIP on that same release.
  5. The release is not in the latest twelve. Drafts are skipped, and we check the latest twelve public releases.
  6. The change is still catching up. Changes can take an hour. Give it a little time and check again.

Give it a go

Ship your next release from GitHub.

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.