ModDevGradle
A Gradle plugin for developing Minecraft mods using NeoForge
Install / Use
/learn @neoforged/ModDevGradleREADME
Gradle Plugin for Developing Minecraft Mods on NeoForge
Check the NeoForged Project Listing for latest releases.
If you are updating to a new major version of the plugin, refer to the list of breaking changes.
Features
- Uses the latest Gradle best practices and is compatible with Gradle 8.8
- Creates the necessary artifacts to compile Minecraft mods for NeoForge
- Runs the game from Gradle or IntelliJ for debugging and testing
- Automatically creates and uses a development-friendly logging configuration for the testing the mod
- Supports the Gradle configuration cache to speed up repeated runs of Gradle tasks
Basic Usage for NeoForge Mods
In gradle.properties:
# Enable Gradle configuration cache if you'd like:
org.gradle.configuration-cache=true
In settings.gradle:
plugins {
// This plugin allows Gradle to automatically download arbitrary versions of Java for you
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0'
}
In build.gradle:
plugins {
// Apply the plugin. You can find the latest version at https://projects.neoforged.net/neoforged/ModDevGradle
id 'net.neoforged.moddev' version '1.0.11'
}
neoForge {
// We currently only support NeoForge versions later than 21.0.x
// See https://projects.neoforged.net/neoforged/neoforge for the latest updates
version = "21.0.103-beta"
// Validate AT files and raise errors when they have invalid targets
// This option is false by default, but turning it on is recommended
validateAccessTransformers = true
runs {
client {
client()
}
data {
data()
}
server {
server()
}
}
mods {
testproject {
sourceSet sourceSets.main
}
}
}
See the example code in the test project.
Vanilla-Mode
In multi-loader projects, you'll often need a subproject for your cross-loader code. This project will also need access to Minecraft classes, but without any loader-specific extensions.
This plugin solves that by offering a "Vanilla-mode" which you enable by specifying a NeoForm version instead of a NeoForge version. NeoForm contains the necessary configuration to produce Minecraft jar-files that you can compile against that contain no other modifications.
In Vanilla-mode, only the client, server and data run types are supported.
Since the plugin includes no mod loader code in this mode, only basic resource- and data packs will be usable in-game.
In build.gradle:
Apply the plugin as usual and use a configuration block like this:
neoForge {
// Look for versions on https://projects.neoforged.net/neoforged/neoform
neoFormVersion = "1.21-20240613.152323"
runs {
client {
client()
}
server {
server()
}
data {
data()
}
}
}
Disabling Decompilation and Recompilation
By default, MDG will use the NeoForm decompilation/recompilation pipeline to produce Minecraft sources and a matching compiled game jar. This leads to a great debugging experience, at the cost of longer setup times.
As of MDG 2.0.124, an alternative pipeline can be used, which will skip decompilation and recompilation entirely.
As of MDG 2.0.136, this pipeline will be used by default in CI/CD pipelines, if the CI environment variable is true.
This is true by default in many CI/CD systems such as GitHub Actions.
To control this setting manually, replace:
neoForge {
version = "..." // or neoFormVersion = "..."
}
By:
neoForge {
enable {
version = "..." // or neoFormVersion = "..."
disableRecompilation = true
}
}
Common Issues
Clicking "Attach Sources" does nothing when viewing a Minecraft class (IntelliJ IDEA)
Sometimes IntelliJ gets into a state where clicking "Attach Sources" while viewing a decompiled Minecraft class will not work.
Reloading the Gradle Project and then clicking "Attach Sources" again will usually fix this problem.
Task idePostSync not found (IntelliJ IDEA)
This error typically happens when switching to ModDevGradle from another plugin with an idePostSync task.
This can be fixed by unregistering the task in IntelliJ IDEA, as follows:
- Open the Gradle tool window on the right, and right-click the Gradle project.

- Click on
Tasks Activation.

- Select the
idePostSynctask and delete it using the-button.

- Sync the Gradle project again.
More Configuration
Runs
Any number of runs can be added in the neoForge { runs { ... } } block.
Every run must have a type. Currently, the supported types are client, data, gameTestServer, server.
The run type can be set as follows:
neoForge {
runs {
<run name> {
// This is the standard syntax:
type = "gameTestServer"
// Client, data and server runs can use a shorthand instead:
// client()
// data()
// server()
// Changes the working directory used for this run.
// The default is the 'run' subdirectory of your project
gameDirectory = project.file('runs/client')
// Add arguments passed to the main method
programArguments = ["--arg"]
programArgument("--arg")
// Add arguments passed to the JVM
jvmArguments = ["-XX:+AllowEnhancedClassRedefinition"]
jvmArgument("-XX:+AllowEnhancedClassRedefinition")
// Add system properties
systemProperties = [
"a.b.c": "xyz"
]
systemProperty("a.b.c", "xyz")
// Set or add environment variables
environment = [
"FOO_BAR": "123"
]
environment("FOO_BAR", "123")
// Optionally set the log-level used by the game
logLevel = org.slf4j.event.Level.DEBUG
// You can change the name used for this run in your IDE
ideName = "Run Game Tests"
// You can disable a run configuration being generated for your IDE
disableIdeRun()
// ... alternatively you can set ideName = ""
// Changes the source set whose runtime classpath is used for this run. This defaults to "main"
// Eclipse does not support having multiple runtime classpaths per project (except for unit tests).
sourceSet = sourceSets.main
// Changes which local mods are loaded in this run.
// This defaults to all mods declared in this project (inside of mods { ... } ).
loadedMods = [mods.<mod name 1>, mods.<mod name 2>]
// Allows advanced users to run additional Gradle tasks before each launch of this run
// Please note that using this feature will significantly slow down launching the game
taskBefore tasks.named("generateSomeCodeTask")
}
}
}
Please have a look at RunModel.java for the list of supported properties. Here is an example that sets a system property to change the log level to debug:
neoForge {
runs {
configureEach {
systemProperty 'forge.logging.console.level', 'debug'
}
}
}
Jar-in-Jar
To embed external Jar-files into your mod file, you can use the jarJar configuration added by the plugin.
External Dependencies
When you want to bundle external dependencies, Jar-in-Jar has to be able to select a single copy of that dependency when it is bundled by multiple mods (possibly even in different versions). To support this scenario, you should set a supported version range to avoid mod incompatibilities.
dependencies {
jarJar(implementation("org.commonmark:commonmark")) {
version {
// The version range your mod is actually compatible with.
// Note that you may receive a *lower* version than your preferred if another
// Mod is only compatible up to 1.7.24, for example, your mod might get 1.7.24 at runtime.
strictly '[0.1, 1.0)'
prefer '0.21.0' // The version actually used in your dev workspace
}
}
}
Version ranges use the Maven version range format:
| Range | Meaning | |---------------|-------------------------------------------------------------------------------| | (,1.0] | x <= 1.0 | | 1.0 | Soft requirement on 1.0. It allows for any version. | | [1.0] | Hard requirement on 1.0 | | [1.2,1.3] | 1.2 <= x <= 1.3 | | [1.0,2.0) | 1.0 <= x < 2.0 | | [1.5,) | x >= 1.5 | | (,1.0],[1.2,) | x <= 1.0 or x >= 1.2. Multiple sets are comma-sepa
Related Skills
node-connect
341.8kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
84.6kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
341.8kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
84.6kCommit, push, and open a PR
