Loaders
Pinned tooling versions
Prism bundles every underlying build plugin on its own classpath at fixed versions:
| Tool | Used for | Pinned version |
|---|---|---|
| Fabric Loom | Fabric (all versions) | 1.16.1 |
| ModDevGradle | NeoForge + Forge 1.17–1.20.1 | 2.0.141 |
| ForgeGradle | LexForge 1.21.1+ | 7.0.25 |
| RetroFuturaGradle | Legacy Forge 1.7.10–1.12.2 | 2.0.2 |
NeoForm versions are not pinned — Prism resolves the right NeoForm version per Minecraft version at sync time and caches the lookup in ~/.gradle/caches/prism/neoform-versions.txt.
If you need a different pinned-tool version (e.g. an alpha for a brand-new Minecraft version, or a hotfix), see Overriding pinned tooling below.
Fabric
Uses Fabric Loom under the hood.
version("1.21.1") {
fabric {
loaderVersion = "0.16.2"
fabricApi("0.102.1")
datagen()
dependencies {
modImplementation("some:fabric-mod:1.0")
}
}
}
| Property | Required | Description |
|---|---|---|
loaderVersion | Yes | Fabric Loader version |
fabricApi() | No | Adds Fabric API as a dependency |
yarn() | No | Use Yarn mappings instead of Mojang |
datagen() | No | Enables Fabric API datagen run |
Mappings
By default, Prism uses official Mojang mappings. To use Yarn instead:
fabric {
loaderVersion = "0.18.6"
yarn("1.21.1+build.3")
}
Yarn mappings are only available for obfuscated versions (pre-26.x). On 26.x, Minecraft is unobfuscated and no mappings are needed.
Access wideners are picked up from common/src/main/resources/{modId}.accesswidener or from the path set via accessWidener() in the version block. On Minecraft 26.1+, use the new class-tweaker format: file {modId}.classtweaker with header classTweaker v1 official. The body syntax (accessible class/method/field, extendable, mutable) is unchanged. The accessWidener field in fabric.mod.json still points at this file (the JSON key kept its old name for back-compat).
Mixins and raw hooks
fabric {
mixins {
config("mymod.mixins.json")
refmap("mymod.refmap.json")
disableAutoDetect()
}
rawLoom { loom -> }
rawProject { project -> }
}
Datagen
When datagen() is called and Fabric API is present, Prism creates a datagen run configuration that uses Fabric API's datagen system. Generated resources output to src/main/generated and are automatically added to the source set.
Run configurations generated: client, server, and optionally datagen.
NeoForge
Uses ModDevGradle under the hood.
version("1.21.1") {
neoforge {
loaderVersion = "21.1.26"
dependencies {
implementation("some:neoforge-mod:1.0")
jarJar("some:library:[1.0,2.0)")
}
}
}
| Property | Required | Description |
|---|---|---|
loaderVersion | Yes | NeoForge version |
Access transformers are picked up from both common/src/main/resources/META-INF/accesstransformer.cfg and the loader's own resources. If no AT file exists but an .accesswidener file is found (via accessWidener() or auto-detection), Prism automatically converts it to AT format.
Mixins and raw hooks
neoforge {
mixins {
config("mymod.mixins.json")
refmap("mymod.refmap.json") // optional: custom refmap filename
disableAutoDetect()
}
rawNeoForge { ext -> }
rawProject { project -> }
}
Datagen
Prism detects the Minecraft version and configures datagen accordingly:
- 1.21.3 and older: Single
datarun - 1.21.4 and newer: Split
clientDataandserverDataruns
Generated resources output to src/generated/resources and are automatically added to the source set.
LexForge (1.21.1+)
Uses ForgeGradle 7 for modern Forge (1.21.1 and later). "LexForge" is MinecraftForge proper — named to distinguish it from NeoForge, which is a separate fork with its own toolchain.
version("1.21.1") {
lexForge {
loaderVersion = "52.0.0"
dependencies {
implementation("some:forge-mod:1.0")
}
}
}
In settings.gradle.kts:
prism {
version("1.21.1") {
lexForge()
}
}
The loader subproject path is :1.21.1:lexforge (directory versions/1.21.1/lexforge/).
| Property | Required | Description |
|---|---|---|
loaderVersion | Yes | Forge version (without MC prefix) |
loaderVersionRange | No | Version range for template expansion |
mappings(c, v) | No | Mappings channel and version |
The Forge dependency is resolved as net.minecraftforge:forge:{mcVersion}-{loaderVersion} via FG7's Minecraft Mavenizer.
Mappings
Prism picks the mappings channel in this order:
- Explicit
mappings("channel", "version")from the DSL - Parchment — if
parchmentMinecraftVersionandparchmentMappingsVersionare set at the version level, Prism uses channelparchmentwith version{parchmentMappingsVersion}-{parchmentMinecraftVersion} - Official — channel
officialwith the Minecraft version
version("1.21.1") {
parchmentMinecraftVersion = "1.21.1"
parchmentMappingsVersion = "2024.11.17"
lexForge {
loaderVersion = "52.0.0"
}
}
Mixins
FG7 does not ship a mixin Gradle extension. Prism still auto-detects .mixins.json configs, adds the Sponge Mixin annotation processor, and writes the MixinConfigs attribute into the jar manifest so Forge discovers them at runtime. Refmap generation uses Sponge Mixin's defaults; to customize (refmap filename, source set binding), apply the org.spongepowered.mixin plugin yourself via rawProject { }.
Raw hooks
lexForge {
loaderVersion = "52.0.0"
rawLexForge { minecraft: MinecraftExtensionForProject -> }
rawProject { project -> }
}
Run configurations generated: client, server, data.
Forge (1.17 - 1.20.1)
Uses ModDevGradle Legacy for Forge 1.17 through 1.20.1.
version("1.20.1") {
forge {
loaderVersion = "47.2.0"
dependencies {
implementation("some:forge-mod:1.0")
}
}
}
| Property | Required | Description |
|---|---|---|
loaderVersion | Yes | Forge version (without MC prefix) |
The version string passed to MDG Legacy is {mcVersion}-{loaderVersion}, e.g. 1.20.1-47.2.0.
Run configurations generated: client, server, data.
Custom remap configurations
forge {
loaderVersion = "47.4.16"
remapConfiguration("optionalMods")
dependencies {
modConfiguration("optionalMods", "curse.maven:jei-238222:7391695")
}
}
Mixins and raw hooks
forge {
mixins {
config("mymod.mixins.json")
refmap("mymod.refmap.json")
}
rawLegacyForge { ext -> }
rawProject { project -> }
}
Every *.mixins.json in the common or forge subproject that declares non-empty mixins/client/server arrays MUST include a top-level "refmap": "<modid>.refmap.json" field. Prism fails the build at configuration time if it's missing — without a refmap, MDG Legacy cannot remap the mixin targets and the mod will crash in production. Fabric is exempt (Loom writes the refmap automatically).
Forge mod dependencies must use mod*
On MDG Legacy, any dependency whose jar contains META-INF/mods.toml is a Forge mod and must be remapped. Declare it via the mod* variants:
forge {
dependencies {
modImplementation("curse.maven:jei-238222:4712866") // correct
// implementation("curse.maven:jei-238222:4712866") // Prism rejects this
}
}
The same rule applies to common { } on MDG Legacy versions, since the common project pulls the Forge jar through NeoForm. Prism resolves each dep, inspects the jar, and fails the build if a Forge mod is declared on a non-mod configuration.
Legacy Forge (1.7.10 - 1.12.2)
Uses RetroFuturaGradle for old Forge versions.
version("1.12.2") {
legacyForge {
mcVersion = "1.12.2"
forgeVersion = "14.23.5.2847"
mappingChannel = "stable" // default
mappingVersion = "39" // default
username = "Developer" // default
useModernJavaSyntax = false // default; set true for Java 17+ syntax via ECJ
accessTransformer("src/main/resources/META-INF/mymod_at.cfg")
// Mixins: if any *.mixins.json lives in src/main/resources and you have
// @Mixin-annotated classes, Prism auto-wires MixinBooter + manifest attrs.
// No extra configuration needed. Optional overrides:
mixinBooter = true // default; set false to disable entirely
mixinBooterVersion = "10.7" // pin a specific MixinBooter version
coreMod("com.example.mymod.MyFMLPlugin") // skip auto-detect of IFMLLoadingPlugin
mixins {
config("extra.mixins.json")
refmap("mymod.refmap.json")
}
// mixin() — legacy tweaker-style registration (rarely needed; auto-detect is preferred)
dependencies {
implementation("some:library:1.0")
}
}
}
| Property | Required | Default | Description |
|---|---|---|---|
mcVersion | Yes | 1.12.2 | Minecraft version |
forgeVersion | Yes | 14.23.5.2847 | Forge version |
mappingChannel | No | stable | MCP mapping channel |
mappingVersion | No | 39 | MCP mapping version |
username | No | Developer | Dev username for run configs |
useModernJavaSyntax | No | false | Enable Java 17+ syntax via ECJ |
mixinBooter | No | true | Auto-add MixinBooter + CleanroomMC maven + AP |
mixinBooterVersion | No | 10.7 | MixinBooter version to pin |
mixin() vs mixins {}: mixin() is a legacy method that registers MixinTweaker in the jar manifest directly. For most projects, auto-detection via mixins {} or the default behavior is sufficient. Use mixin() only if you need the MixinTweaker registered even when no @Mixin annotations are detected.
coreMod(fqn) overrides the auto-detected IFMLLoadingPlugin class. Prism scans src/main/{java,kotlin} for a class annotated with @IFMLLoadingPlugin.Name or implementing IFMLLoadingPlugin. If the scan produces incorrect results or you use a generated class, set it explicitly here.
Requires the GTNH maven in pluginManagement:
maven { url = uri("https://nexus.gtnewhorizons.com/repository/public/") }
Java 8 toolchain with Azul JDK. Run configurations: runClient, runServer.
Mixins on 1.12.2
On 1.12.2 Sponge Mixin is loaded via a coremod. Prism automates the entire chain when it sees mixin sources in the project:
- Adds the CleanroomMC maven (
https://repo.cleanroommc.com/releases). - Adds
zone.rong:mixinbooter:<version>as bothimplementationandannotationProcessor(non-transitive). - Auto-registers every
*.mixins.jsonundersrc/main/resources/via the jar'sMixinConfigsmanifest attribute. - Writes these manifest attributes on the jar task:
FMLCorePlugin = <FQN>— auto-detected from any class with@IFMLLoadingPlugin.Nameorimplements IFMLLoadingPlugininsrc/main/{java,kotlin}. Override withcoreMod("com.example.MyPlugin"). If no class is found, this attribute is omitted (late-mixin mods don't need it).FMLCorePluginContainsFMLMod = "true"ForceLoadAsMod = "true"
"Has mixin sources" means at least one @Mixin( annotation is present, or the mixins { } block declares explicit configs. If neither applies, Prism does nothing (non-mixin mods stay untouched).
Use rawProject {} when you need plain RetroFuturaGradle customization that Prism does not model directly.
Custom run configurations
Every loader gets default runs (client, server, data). You can add more:
fabric {
loaderVersion = "0.18.6"
fabricApi("0.116.9+1.21.1")
runs {
client("testClient") {
username = "Dev"
}
server("secondServer") {
jvmArg("-Xmx4G")
}
}
}
neoforge {
loaderVersion = "21.1.222"
runs {
client("debugClient") {
username = "TestPlayer"
systemProperty("forge.logging.console.level", "trace")
}
}
}
Custom runs appear in IntelliJ alongside the defaults. The username field is optional and sets the in-game player name for dev runs.
Run DSL methods
| Method / Property | Description |
|---|---|
client(name) | Creates a client run |
server(name) | Creates a server run |
run(name) { … } | Fully custom run, set type inside |
client() (inside run {}) | Set run type to CLIENT |
server() (inside run {}) | Set run type to SERVER |
data() (inside run {}) | Set run type to DATA |
clientData() (inside run {}) | Set run type to CLIENT_DATA (NeoForge 1.21.4+) |
serverData() (inside run {}) | Set run type to SERVER_DATA (NeoForge 1.21.4+) |
username = "..." | Set dev player name |
jvmArg(arg) | Add JVM argument |
programArg(arg) | Add program argument |
systemProperty(k, v) | Add system property |
runDir = "..." | Custom run directory |
ideConfigGenerated = true | Whether an IDE run config is generated (default: true) |
CLIENT_DATA and SERVER_DATA run types are used by NeoForge's split datagen on 1.21.4+. Prism registers these automatically — the run {} type setters are available if you need to create additional datagen runs manually.
Kotlin support
Enable Kotlin for all subprojects of a version:
version("1.21.1") {
kotlin() // uses Kotlin 2.1.20 by default
// or
kotlin("2.0.21") // specific version
fabric { loaderVersion = "0.16.2" }
neoforge { loaderVersion = "21.1.26" }
}
This applies org.jetbrains.kotlin.jvm to both the common and all loader subprojects, and configures the JVM target to match the Minecraft version's Java requirement.
The Kotlin plugin must be resolvable from your pluginManagement repositories.
Overriding pinned tooling
The four build plugins listed in Pinned tooling versions are loaded as transitive dependencies of the Prism settings plugin. They do not pass through the plugin-marker mechanism, so the usual pluginManagement.resolutionStrategy.eachPlugin knob is silently ignored for them.
The override happens on the settings buildscript classpath instead. Add a buildscript { configurations.classpath { ... } } block at the top of settings.gradle.kts — before the plugins { } block — and substitute the version you want:
// settings.gradle.kts — must be the first block in the file
buildscript {
configurations.classpath {
resolutionStrategy.eachDependency {
when {
requested.group == "net.fabricmc" && requested.name == "fabric-loom" -> {
useVersion("1.17.0-alpha.7")
because("need class-tweaker v2 support for 26.x")
}
requested.group == "net.neoforged" && requested.name == "moddev-gradle" -> {
useVersion("2.0.150")
}
requested.group == "net.minecraftforge" && requested.name == "forgegradle" -> {
useVersion("7.1.0")
}
requested.group == "com.gtnewhorizons" && requested.name == "retrofuturagradle" -> {
useVersion("2.1.0")
}
}
}
}
}
pluginManagement {
repositories {
maven { url = uri("https://maven.fabricmc.net/") }
maven { url = uri("https://maven.neoforged.net/releases") }
maven { url = uri("https://maven.minecraftforge.net/") }
maven { url = uri("https://nexus.gtnewhorizons.com/repository/public/") }
gradlePluginPortal()
}
}
plugins {
id("dev.prism.settings") version "+"
}
Substitute only the tools you actually need to bump — the when { } arms are independent. Order is critical: the buildscript { } block must appear before plugins { }, or the Prism jar (and the bundled tooling) is already on the classpath by the time your substitution runs.
Prism is compiled against each tool's pinned version's API. Bumps within the same minor line (1.16.x, 2.0.x, 7.0.x, 2.0.x) generally work; cross-minor or cross-major bumps may compile but break at runtime if the upstream removed or renamed an API symbol Prism touches. Use at your own risk and report breakage so the pin can be raised properly.