Minecraft mod development framework, used by NeoForge and FML for the Gradle build system.
For a quick start, see how the NeoForge Mod Development Kit uses NeoGradle, or see our official Documentation.
To see the latest available version of NeoGradle, visit the NeoForged project page.
NeoGradle is separated into several different plugins that can be applied independently of each other.
This plugin is used for building mods with NeoForge. As a modder, this will in many cases be the only plugin you use.
plugins {
id 'net.neoforged.gradle.userdev' version '<neogradle_version>'
}
dependencies {
implementation 'net.neoforged:neoforge:<neoforge_version>'
}
When this plugin detects a dependency on NeoForge, it will spring into action and create the necessary NeoForm runtime tasks to build a usable Minecraft JAR-file that contains the requested NeoForge version. It additionally (if configured to do so via conventions, which is the default) will create runs for your project, and add the necessary dependencies to the classpath of the run.
Using gradles modern version catalog feature means that dependencies are added at the very last moment possible, regardless of that is during script evaluation or not. This means that if you use this feature it might sometimes not be possible to configure the default runs exactly as you wished. In that case it might be beneficial to disable the conventions for runs, and configure them manually.
See the following example:
lib.versions.toml:
[versions]
# Neoforge Settings
neoforge = "+"
[libraries]
neoforge = { group = "net.neoforged", name = "neoforge", version.ref = "neoforge" }
build.gradle:
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation(libs.neoforge)
}
runs {
configureEach { run ->
run.modSource sourceSets.main
}
client { }
server { }
datagen { }
gameTestServer { }
junit { }
}
You do not need to create all five of the different runs, only the ones you need. This is because at the point where gradle actually adds the dependency, we can not create any further runs, yet we can still configure them for you when the dependency is added.
The common plugin provides dependency management for extra-jar of minecraft. This is a special jar containing just the resources and assets of minecraft, no code. This is useful for mods that want to depend on the resources of minecraft, but not the code.
plugins {
id 'net.neoforged.gradle.common' version '<neogradle_version>'
}
dependencies {
implementation "net.minecraft:client:<minecraft_version>:client-extra"
}
The common plugin provides support for jar-in-jar dependencies, both for publishing and when you consume them.
If you want to depend on a project that uses jar-in-jar dependencies, you can do so by adding the following to your build.gradle:
dependencies {
implementation "project.with:jar-in-jar:1.2.3"
}
Obviously you need to replace project.with:jar-in-jar:1.2.3
with the actual coordinates of the project you want to depend on,
and any configuration can be used to determine the scope of your dependency.
If you want to publish a jar-in-jar dependency, you can do so by adding the following to your build.gradle:
dependencies {
jarJar("project.you.want.to:include-as-jar-in-jar:[my.lowe.supported.version,potentially.my.upper.supported.version)") {
version {
prefer "the.version.you.want.to.use"
}
}
}
Important here to note is that specifying a version range is needed. Jar-in-jar dependencies are not supported with a single version, directly.
If you need to specify a single version, you can do so by specifying the same version for both the lower and upper bounds of the version range: [the.version.you.want.to.use]
.
When dependency gets moved from one GAV to another, generally a transfer coordinate gets published, either via maven-metadata.xml, a seperate pom file, or via gradles available-at metadata. This can cause the version of the dependency to be different from the version you specified. It is best that you update your dependency to the new GAV to prevent problems and confusion in the future.
The common plugin provides a way to manage runs in your project. Its main purpose is to ensure that whether you use the vanilla, neoform, platform or userdev modules, you can always manage your runs in the same way.
plugins {
id 'net.neoforged.gradle.common' version '<neogradle_version>'
}
runs {
//...Run configuration
}
When you create a run in your project, it will initially be empty. If you do not use a run type, or clone the configuration from another run, as described below, you will have to configure the run yourself.
runs {
someRun {
isIsSingleInstance true //This will make the run a single instance run, meaning that only one instance of the run can be run at a time
mainClass 'com.example.Main' //This will set the main class of the run
arguments 'arg1', 'arg2' //This will set the arguments of the run
jvmArguments '-Xmx4G' //This will set the jvm arguments of the run
isClient true //This will set the run to be a client run
isServer true //This will set the run to be a server run
isDataGenerator true //This will set the run to be a data gen run
isGameTest true //This will set the run to be a game test run
isJUnit true //This will set the run to be a junit run, indicating that a Unit Test environment should be used and not a normal run
environmentVariables 'key1': 'value1', 'key2': 'value2' //This will set the environment variables of the run
systemProperties 'key1': 'value1', 'key2': 'value2' //This will set the system properties of the run
classPath.from project.configurations.runtimeClasspath //This will add an element to just the classpath of this run
shouldBuildAllProjects true //This will set the run to build all projects before running
workingDirectory file('some/path') //This will set the working directory of the run
}
}
Beyond these basic configurations you can always look at the Runs DSL object to see what other options are available.
If you are using run types that do not come from an SDK (like those that the userdev plugin), you can configure them as follows:
runs {
someRun {
isIsSingleInstance true //This will make the runs of this type a single instance run, meaning that only one instance of the run can be run at a time
mainClass 'com.example.Main' //This will set the main class of the runs of this type
arguments 'arg1', 'arg2' //This will set the arguments of the runs of this type
jvmArguments '-Xmx4G' //This will set the jvm arguments of the runs of this type
isClient true //This will set the run to be a client runs of this type
isServer true //This will set the run to be a server runs of this type
isDataGenerator true //This will set the run to be a data gen runs of this type
isGameTest true //This will set the run to be a game test runs of this type
isJUnit true //This will set the run to be a junit runs of this type, indicating that a Unit Test environment should be used and not a normal run
environmentVariables 'key1': 'value1', 'key2': 'value2' //This will set the environment variables of the runs of this type
systemProperties 'key1': 'value1', 'key2': 'value2' //This will set the system properties of the runs of this type
classPath.from project.configurations.runtimeClasspath //This will add an element to just the classpath of this runs of this type
}
}
The common plugin manages the existence of runs, but it on its own does not create or configure a run. It just ensures that when you create a run tasks, and IDE runs, are created for it, based on the configuration of the run itself.
To configure a run based on a given template, run types exist. And if you use the userdev plugin for example then it will load the run types from the SDKs you depend on and allow you to configure runs based on those types.
First and foremost by default the common plugin will configure any run that is named identical to a run type with that run type. You can disable that for a run by setting:
runs {
someRun {
configureFromTypeWithName false
}
}
If you want to configure a run based on a run type, you can do so by setting:
runs {
someRun {
runType 'client' //In case you want to configure the run type based on its name
configure runTypes.client //In case you want to configure the run type based on the run type object, this might not always be possible, due to the way gradle works
//The following method is deprecated and will be removed in a future release
configure 'client'
}
}
Both of these will throw an exception if the run type could not be found during realization of the run to a task or ide run.
When a run is added the common plugin will also inspect it and figure out if any SDK or MDK was added to any of its sourcesets, if so, it gives that SDK/MDK a chance to add its own settings to the run. This allows provides like NeoForge to preconfigure runs for you.
However, if you set up the run as follows:
runs {
someRun {
modSource sourceSets.some_version_a_sourceset
modSource sourceSets.some_version_b_sourceset
}
}
where the relevant sourcesets have a dependency in their compile classpath on the given sdk version, and those differ, and error will be raised. This is because the common plugin can not determine which version of the sdk to use for the run. To fix this, choose one of the versions and add it to the run:
runs {
someRun {
modSource sourceSets.some_version_a_sourceset
}
}
or
runs {
someRun {
modSource sourceSets.some_version_b_sourceset
}
}
Additionally, you can also clone a run into another run:
runs {
someRun {
run 'client' //In case you want to clone the client run into the someRun
configure runTypes.client //In case you want to clone the client run type into the someRun
}
}
The DevLogin tool is a tool that allows you to log in to a Minecraft account without having to use the Minecraft launcher, during development. During first start it will show you a link to log in to your Minecraft account, and then you can use the tool to log in to your account. The credentials are cached on your local machine, and then reused for future logins, so that re-logging is only needed when the tokens expire. This tool is used by the runs subsystem to enable logged in plays on all client runs. The tool can be configured using the following properties:
neogradle.subsystems.devLogin.enabled=<true/false>
By default, the subsystem is enabled, and it will prepare everything for you to log in to a Minecraft account, however you will still need to enable it on the runs you want. If you want to disable this you can set the property to false, and then you will not be asked to log in, but use a random non-signed in dev account.
If you want to configure the dev login tool per run, you can do so by setting the following properties in your run configuration:
runs {
someRun {
devLogin {
enabled true
}
}
}
This will enable the dev login tool for this run. By default, the dev login tool is disabled, and can only be enabled for client runs.
[!WARNING] If you enable the dev login tool for a non-client run, you will get an error message.
Additionally, it is possible to use a different user profile for the dev login tool, by setting the following property in your run configuration:
runs {
someRun {
devLogin {
profile '<profile>'
}
}
}
If it is not set then the default profile will be used. See the DevLogin documentation for more information on profiles: DevLogin by Covers1624
To add the dev login tool to your run we create a custom configuration to which we add the dev login tool. This configuration is created for the first source-set you register with the run as a mod source set. The suffix for the configuration can be configured to your personal preference, by setting the following property in your gradle.properties:
neogradle.subsystems.devLogin.configurationSuffix=<suffix>
By default, the suffix is set to "DevLoginLocalOnly". We use this approach to create a runtime only configuration, that does not leak to other consumers of your project.
The RenderDoc tool is a tool that allows you to capture frames from your game, and inspect them in its frame debugger. Our connector implementation can be optionally injected to start RenderDoc with your game.
If you want to configure the render doc tool per run, you can do so by setting the following properties in your run configuration:
runs {
someRun {
renderDoc {
enabled true
}
}
}
This will enable the render doc tool for this run. By default, the render doc tool is disabled, and can only be enabled for client runs.
[!WARNING] If you enable the render doc tool for a non-client run, you will get an error message.
Gradle supports resource processing out of the box, using the processResources
task (or equivalent for none main sourcesets).
However, no IDE supports this out of the box. To provide you with the best experience NeoGradle, will run the processResources
task for you, before you run the game.
If you are using IDEA and have enabled the "Build and Run using IntelliJ IDEA" option, then NeoGradle will additionally modify its runs,
to ensure that the processResources
task is run before the game is started, and redirects its output to a separate location in your build directory, and these processed
resources are used during your run.
[!WARNING] This means that the resource files created by ideas compile process are not used, and you should not rely on them being up-to-date.
Due to the way IDEA starts Unit Tests from the gutter, it is not possible to reconfigure these kinds of tests, if you are running with the IDEA testing engine. To support this scenario, by default NeoGradle will reconfigure IDEAs testing defaults to support running these tests within a unit test environment.
However, due to the many constructs it is not possible to configure the defaults correctly for everybody, if you have a none standard testing setup, you can configure the defaults like so:
idea {
unitTests {
//Normal run properties, and sourceset configuration as if you are configuring a run:
modSource sourceSets.anotherTestSourceSet
}
}
If you want to disable this feature, you can disable the relevant conventions, see Disabling conventions.
The common plugin provides a way to manage sourcesets in your project a bit easier. In particular, it allows you to easily depend on a different sourceset, or inherit its dependencies.
[!WARNING]
However, it is important to know that you can only do this for sourcesets from the same project. NeoGradle will throw an exception if you try to depend on a sourceset from another project.
If you want to inherit the dependencies of another sourceset, you can do so by adding the following to your build.gradle:
sourceSets {
someSourceSet {
inherit.from sourceSets.someOtherSourceSet
}
}
If you want to depend on another sourceset, you can do so by adding the following to your build.gradle:
sourceSets {
someSourceSet {
depends.on sourceSets.someOtherSourceSet
}
}
This plugin enables use of the NeoForm runtime and allows projects to depend directly on deobfuscated but otherwise unmodified Minecraft artifacts.
This plugin is used internally by other plugins and is usually only needed for advanced use cases.
plugins {
id 'net.neoforged.gradle.neoform' version '<neogradle_version>'
}
dependencies {
// For depending on a Minecraft JAR-file with both client- and server-classes
implementation "net.minecraft:neoform_joined:<neoform-version>"
// For depending on the Minecraft client JAR-file
implementation "net.minecraft:neoform_client:<neoform-version>"
// For depending on the Minecraft dedicated server JAR-file
implementation "net.minecraft:neoform_server:<neoform-version>"
}
To get human-readable parameter names in decompiled Minecraft source-code, as well as Javadocs, crowdsourced data from the Parchment project can be applied to the Minecraft source-code before it is recompiled.
This is currently only supported when applying the NeoGradle userdev Plugin.
The most basic configuration is using the following properties in gradle.properties:
neogradle.subsystems.parchment.minecraftVersion=1.20.2
neogradle.subsystems.parchment.mappingsVersion=2023.12.10
The subsystem also has a Gradle DSL and supports more parameters, explained in the following Gradle snippet:
subsystems {
parchment {
// The Minecraft version for which the Parchment mappings were created.
// This does not necessarily need to match the Minecraft version your mod targets
// Defaults to the value of Gradle property neogradle.subsystems.parchment.minecraftVersion
minecraftVersion = "1.20.2"
// The version of Parchment mappings to apply.
// See https://parchmentmc.org/docs/getting-started for a list.
// Defaults to the value of Gradle property neogradle.subsystems.parchment.mappingsVersion
mappingsVersion = "2023.12.10"
// Overrides the full Maven coordinate of the Parchment artifact to use
// This is computed from the minecraftVersion and mappingsVersion properties by default.
// If you set this property explicitly, minecraftVersion and mappingsVersion will be ignored.
// The built-in default value can also be overriden using the Gradle property neogradle.subsystems.parchment.parchmentArtifact
// parchmentArtifact = "org.parchmentmc.data:parchment-$minecraftVersion:$mappingsVersion:checked@zip"
// Set this to false if you don't want the https://maven.parchmentmc.org/ repository to be added automatically when
// applying Parchment mappings is enabled
// The built-in default value can also be overriden using the Gradle property neogradle.subsystems.parchment.addRepository
// addRepository = true
// Can be used to explicitly disable this subsystem. By default, it will be enabled automatically as soon
// as parchmentArtifact or minecraftVersion and mappingsVersion are set.
// The built-in default value can also be overriden using the Gradle property neogradle.subsystems.parchment.enabled
// enabled = true
}
}
The settings used by the decompiler when preparing Minecraft dependencies can be overridden using Gradle properties. This can be useful to run NeoGradle on lower-end machines, at the cost of slower build times.
Property | Description |
---|---|
neogradle.subsystems.decompiler.maxMemory |
How much heap memory is given to the decompiler. Can be specified either in gigabyte (4g ) or megabyte (4096m ). |
neogradle.subsystems.decompiler.maxThreads |
By default the decompiler uses all available CPU cores. This setting can be used to limit it to a given number of threads. |
neogradle.subsystems.decompiler.logLevel |
Can be used to override the decompiler loglevel. |
The settings used by Neogradle for recompiling the decompiled Minecraft source code can be customized using Gradle properties.
Property | Description |
---|---|
neogradle.subsystems.recompiler.maxMemory |
How much heap memory is given to the decompiler. Can be specified either in gigabyte (4g ) or megabyte (4096m ). Defaults to 1g . |
neogradle.subsystems.recompiler.jvmArgs |
Pass arbitrary JVM arguments to the forked Gradle process that runs the compiler. I.e. -XX:+HeapDumpOnOutOfMemoryError |
neogradle.subsystems.recompiler.args |
Pass additional command line arguments to the Java compiler. |
neogradle.subsystems.recompiler.shouldFork |
Indicates whether or not a process fork should be used for the recompiler. (Default is true). |
This implements run specific dependency management for the classpath of a run. In the past this had to happen via a manual modification of the "minecraft_classpath" token, however tokens don't exist anymore as a component that can be configured on a run. It was as such not possible to add none FML aware libraries to your classpath of a run. This PR enables this feature again.
dependencies {
implementation 'some:library:1.2.3'
}
runs {
testRun {
dependencies {
runtime 'some:library:1.2.3'
}
}
}
configurations {
libraries {}
implementation.extendsFrom libraries
}
dependencies {
libraries 'some:library:1.2.3'
}
runs {
testRun {
dependencies {
runtime project.configurations.libraries
}
}
}
The dependency handler on a run works very similar to a projects own dependency handler, however it has only one "configuration" available to add dependencies to: "runtime". Additionally, it provides a method to use when you want to turn an entire configuration into a runtime dependency.
In general, we suggest, no strongly encourage, to not use fat jars for this solution. The process of creating a fat jar with all the code from your sibling projects is difficult to model in a way that is both correct and efficient for a dev project, especially if the sibling project does not use NeoGradle.
If it is possible to use a NeoGradle module (for example the Vanilla module, instead of VanillaGradle) then you can use the source-set's mod identifier:
sourceSets {
main {
run {
modIdentifier '<some string that all projects in your fat jar have in common>'
}
}
}
The value of the modIdentifier does not matter here, all projects with the same source-set mod identifier will be included in the same fake fat jar when running your run.
If the sibling project does not use NeoGradle, then you have to make sure that its Manifest is configured properly:
FMLModType: GAMELIBRARY #Or any other mod type that is not a mod, like LIBRARY
Automatic-Module-Name: '<some string that is unique to this project>'
[!CAUTION] If you do this, then your sibling projects are not allowed to contain a class in the same package! This is because no two modules are allowed to contain the same package. If you have two sibling projects with a class in the same package, then you will need to move one of them!
To include the sibling project in your run, you need to add it as a modSource to your run:
runs {
someRun {
modSources {
add project.sourceSets.main // Adds the owning projects main sourceset to a group based on that sourcesets mod identifier (could be anything here, depending on the sourcesets extension values, or the project name)
add project(':api').sourceSets.main // Assuming the API project is not using NeoGradle, this would add the api project to a group using the `api` key, because the default mod identifier for non-neogradle projects is the projects name, here api
local project(':api').sourceSets.main // Assuming the API project is not using NeoGradle, this would add the api project to a group using the owning projects name, instead of the api projects name as a fallback (could be anything here, depending on the sourcesets extension values, or the project name)
add('something', project(':api').sourceSets.main) // This hardcodes the group identifier to 'something', performing no lookup of the mod identifier on the sourceset, or using the owning project, or the sourcesets project.
}
}
}
No other action is needed.
By default, conventions are enabled. If you want to disable conventions, you can do so by setting the following property in your gradle.properties:
neogradle.subsystems.conventions.enabled=false
We will consider the conventions to be enabled going forward, so if you want to disable them, you will have to do so explicitly.
NeoGradle will add several Configurations
to your project.
This convention can be disabled by setting the following property in your gradle.properties:
neogradle.subsystems.conventions.configurations.enabled=false
Per SourceSet the following configurations are added, where XXX is the SourceSet name:
[!NOTE] For this to work, your SourceSets need to be defined before your dependency block.
Per Run the following configurations are added:
[!NOTE] For this to work, your Runs need to be defined before your dependency block.
Globally the following configurations are added:
This configuration is used to add dependencies to your local projects runtime only, without exposing them to the runtime of other projects. Requires source set conventions to be enabled
This configuration is used to add dependencies to the local runtime of the runs you add the SourceSets too, without exposing them to the runtime of other runs. Requires source set conventions to be enabled
This configuration is used to add dependencies to the runtime of a specific run only, without exposing them to the runtime of other runs.
This configuration is used to add dependencies to the runtime of all runs.
To disable the sourceset management, you can set the following property in your gradle.properties:
neogradle.subsystems.conventions.sourcesets.enabled=false
By default, the current projects main sourceset is automatically included in its runs. If you want to disable this, you can set the following property in your gradle.properties:
neogradle.subsystems.conventions.sourcesets.automatic-inclusion=false
If you want to disable this, you can set the following property in your gradle.properties:
neogradle.subsystems.conventions.sourcesets.automatic-inclusion=false
This is equivalent to setting the following in your build.gradle:
runs {
configureEach { run ->
run.modSource sourceSets.main
}
}
By default, the local run runtime configuration of a sourceset is automatically included in the runs configuration of the run. If you want to disable this, you can set the following property in your gradle.properties:
neogradle.subsystems.conventions.sourcesets.automatic-inclusion-local-run-runtime=false
This is equivalent to setting the following in your build.gradle:
runs {
configureEach { run ->
run.dependencies {
runtime sourceSets.main.configurations.localRunRuntime
}
}
}
If this functionality is disabled then the relevant configurations local run runtime configurations will not be created.
To disable the IDE integrations, you can set the following property in your gradle.properties:
neogradle.subsystems.conventions.ide.enabled=false
To disable the IDEA integration, you can set the following property in your gradle.properties:
neogradle.subsystems.conventions.ide.idea.enabled=false
If you have configured your IDEA IDE to run with its own compiler, you can disable the autodetection of the IDEA compiler by setting the following property in your gradle.properties:
neogradle.subsystems.conventions.ide.idea.compiler-detection=false
This will set the DSL property:
idea {
runs {
runWithIdea = true / false
}
}
If you want to change the output directory of the IDEA compiler, you can set the following property in your gradle.properties:
neogradle.subsystems.conventions.ide.idea.compiler-output-dir=<path>
By default, this is set to 'out', and configured in the DSL as:
idea {
runs {
outDirectory = '<path>'
}
}
By default, the import in IDEA is run during the sync task. If you want to disable this, and use a post sync task, you can set the following property in your gradle.properties:
neogradle.subsystems.conventions.ide.idea.use-post-sync-task=true
By default, the IDEA unit test templates are not reconfigured to support running unit tests from the gutter. You can enable this behavior by setting the following property in your gradle.properties:
neogradle.subsystems.conventions.ide.idea.reconfigure-unit-test-templates=true
To disable the runs conventions, you can set the following property in your gradle.properties:
neogradle.subsystems.conventions.runs.enabled=false
By default, a run is created for each type of run. If you want to disable this, you can set the following property in your gradle.properties:
neogradle.subsystems.conventions.runs.create-default-run-per-type=false
If you want to enable the dev login tool for all client runs, you can set the following property in your gradle.properties:
neogradle.subsystems.conventions.runs.devlogin.conventionForRun=true
This will enable the dev login tool for all client runs, unless explicitly disabled.
If you want to enable the render doc tool for all client runs, you can set the following property in your gradle.properties:
neogradle.subsystems.conventions.runs.renderdoc.conventionForRun=true
This will enable the render doc tool for all client runs, unless explicitly disabled.
To configure tools used by different subsystems of NG, the subsystems dsl and properties can be used to configure the following tools:
This tool is used by the parchment subsystem to apply its names and javadoc, as well as by the source access transformer system to apply its transformations. The following properties can be used to configure the JST tool:
neogradle.subsystems.tools.jst=<artifact coordinate for jst cli tool>
This tool is used by the dev login subsystem in runs to enable Minecraft authentication in client runs. The following properties can be used to configure the DevLogin tool:
neogradle.subsystems.tools.devLogin=<artifact coordinate for devlogin cli tool>
More information on the relevant tool, its released version and documentation can be found here: DevLogin by Covers1624
This tool is used by the RenderDoc subsystem in runs to allow capturing frames from the game in client runs. The following properties can be used to configure the RenderDoc tool:
neogradle.subsystems.tools.renderDoc.path=<path to the RenderDoc download and installation directory>
neogradle.subsystems.tools.renderDoc.version=<version of RenderDoc to use>
neogradle.subsystems.tools.renderDoc.renderNurse=<artifact coordinate for rendernurse agent tool>
More information on the relevant tool, its released version and documentation can be found here: RenderDoc and RenderNurse
NeoGradle has a centralized cache that can be used to store the decompiled Minecraft sources, the recompiled Minecraft sources, and other task outputs of complex tasks. The cache is enabled by default, and can be disabled by setting the following property in your gradle.properties:
net.neoforged.gradle.caching.enabled=false
You can clean the artifacts that are stored in the cache by running the following command:
./gradlew cleanCache
This command is also automatically run, when you run the clean task. The command will check if the stored artifact count is higher than the configured threshold, and if so, remove the oldest artifacts until the count is below the threshold. The count is configured by the following property in your gradle.properties:
net.neoforged.gradle.caching.maxCacheSize=<number>
There are two properties you can tweak to get more information about the cache:
net.neoforged.gradle.caching.logCacheHits=<true/false>
and
net.neoforged.gradle.caching.debug=<true/false>
The first property will log when a cache hit occurs, and the second property will log more information about the cache in general, including how hashes are calculated. If you are experiencing issues with the cache, you can enable these properties to get more information about what is happening.