6 Things Worth Knowing About Neoforge Version Environment Variables
Neoforge’s versioning system relies on environment variables to manage compatibility layers. These aren’t just arbitrary strings; they follow a structured hierarchy that determines load order, dependency resolution, and even security sandboxes. Below are six critical aspects most modders misunderstand.1. The Core Variables and Their Hierarchy
Neoforge exposes three primary environment variables that define its runtime context: - `NEOFORGE_VERSION`: The target Neoforge API version (e.g., `20.4.123`). - `MODLOADER_VERSION`: The modloader’s internal version (often aligned with Neoforge but may differ in forks). - `MC_VERSION`: The underlying Minecraft version (e.g., `1.20.1`). These variables are read in a specific order: first from the system environment, then from the modloader’s configuration files, and finally from the `gradle.properties` if present. A mismatch here—such as setting `NEOFORGE_VERSION=20.4` while using a 20.3 modloader—will trigger a hard fail during initialization. The hierarchy isn’t just about order; it’s about fallback safety. If a mod explicitly checks `System.getenv("NEOFORGE_VERSION")` but the variable is unset, Neoforge defaults to the version embedded in the modloader JAR. This behavior explains why some mods work in "auto-detect" mode but fail when manually overridden.2. How Variables Affect Dependency Resolution
Neoforge uses these variables to construct a dependency graph before loading any mods. The process begins with the `mods.toml` files, where each mod declares its required Neoforge version range. If a mod specifies `neoforge=[20.3,20.5)`, but the environment variable points to `20.4.123`, the modloader will either: - Load the mod with a warning (if the range is inclusive). - Skip the mod entirely (if the range is exclusive). - Crash with a `VersionConflictException` (if the mod is hardcoded to a specific patch level). This system is why modpacks often bundle a `version.json` file alongside the Neoforge JAR: it pre-defines the expected environment variables to avoid runtime surprises. Without it, the modloader defaults to the highest installed version, which may not match what the mods were tested against.3. Debugging Crashes Through Environment Inspection
When a modded Minecraft instance crashes with an error like `Incompatible mixin version`, the first step is to inspect the active environment variables. Neoforge provides two ways to expose them: 1. Launch arguments: Add `-Dneoforge.debug=true` to the JVM arguments. This dumps all version-related variables to the console at startup. 2. Log inspection: Check the `neoforge.log` file in `.minecraft/logs/` for lines like: ``` [NeoForge] Active environment: NEOFORGE_VERSION=20.4.123, MODLOADER_VERSION=0.20.4, MC_VERSION=1.20.1 ``` These logs often reveal hidden conflicts. For example, a mod might claim to support "Neoforge 20.4+" but internally check for `System.getProperty("neoforge.version")` instead of the environment variable. The discrepancy can lead to false positives in compatibility checks.4. Overriding Variables for Legacy Mods
Some older mods or custom modloaders require manual environment variable overrides. This is done via: - System properties: Pass `-Dneoforge.version=20.3` to the JVM. - Environment files: Create a `.env` file in the modloader directory with: ``` NEOFORGE_VERSION=20.3.112 MODLOADER_VERSION=0.20.3 ``` - Gradle overrides: In `build.gradle`, add: ```groovy systemProperties 'neoforge.version': '20.3.112' ``` Warning: Overriding these variables can break mod interactions. For instance, setting `NEOFORGE_VERSION` to an older patch may cause security warnings or missing features in newer mods. Use this only as a last resort for legacy compatibility.5. The Role of Environment Variables in Multi-Loaders
Neoforge isn’t the only modloader in the ecosystem. When mixing loaders—such as Neoforge with Fabric or Lithium—the environment variables become a battleground. For example: - Fabric uses `fabric-loader.version` instead of `MODLOADER_VERSION`. - Lithium modifies the `minecraft.version` property to include its own suffixes. In such cases, Neoforge’s environment variables take precedence, but the modloader may silently ignore them if it detects a conflicting loader. This is why some modpacks ship with a loader isolation layer, where each loader runs in a separate JVM instance with its own environment scope.6. Security Implications of Hardcoded Variables
A lesser-known risk involves mods that hardcode environment variable checks instead of using Neoforge’s APIs. For example: ```java if (!System.getenv("NEOFORGE_VERSION").startsWith("20.4")) { throw new RuntimeException("Unsupported Neoforge version!"); } ``` This approach is fragile because: - It bypasses Neoforge’s version resolution logic. - It can be exploited by attackers to trigger false positives (e.g., via environment spoofing). - It fails in containerized environments where system variables are restricted. Neoforge’s official documentation recommends using `FMLEnvironment.getVersion()` or `ModLoader.get().getVersion()` instead, as these methods are sandboxed and version-aware.
How These Facts Connect
The six points above reveal a system where environment variables serve as both a compatibility bridge and a single point of failure. On one hand, they allow mods to declare dependencies dynamically, enabling cross-version support. On the other, they create a fragile chain where a single misconfiguration can unravel an entire modpack. The hierarchy of variable sources—system > config > embedded—explains why some issues persist even after updating mods: the environment might still point to an older version due to cached configurations. The dependency graph isn’t just about versions; it’s about trust. Mods rely on Neoforge to provide accurate environment variables, but if a modloader or pack builder overrides them without validation, the entire ecosystem risks instability. This is why tools like Modrinth’s version resolver or FTB’s pack builder automate environment variable checks—manual intervention is error-prone, and the consequences are often catastrophic.| Aspect | Neoforge’s Default Behavior | Common Pitfall | Recommended Fix | Security Risk |
|---|---|---|---|---|
| Variable Hierarchy | System > Config > Embedded | Cached old variables in config files | Clear config cache or use `-Dneoforge.reset=true` | None (unless manually overridden) |
| Dependency Resolution | Checks `mods.toml` against active variables | Mods hardcoding `System.getenv()` | Use `FMLEnvironment.getVersion()` | Environment spoofing attacks |
| Debugging | Logs variables on `-Dneoforge.debug=true` | Ignoring log warnings | Inspect `neoforge.log` first | None |
| Multi-Loader Conflicts | Neoforge variables take precedence | Mixed loader environments | Use isolation layers or separate instances | Loader hijacking |
| Legacy Overrides | Allows manual `-D` overrides | Breaking newer mods | Test in a clean instance first | Version rollback vulnerabilities |
Conclusion
Neoforge’s environment variables are more than technical details—they’re the contract between mods, modloaders, and the Minecraft runtime. Ignoring them leads to silent failures, while misconfiguring them can turn a stable modpack into a debugging nightmare. The key takeaway is that these variables aren’t just for developers; they’re a tool for auditing modpacks, resolving conflicts, and ensuring security. For modpack builders, the lesson is clear: document your environment variables. For modders, it’s about using Neoforge’s APIs instead of raw environment checks. And for players? Understanding these variables means you can troubleshoot crashes with precision, rather than guessing which mod is at fault.Comprehensive FAQs
Q: Why does my modpack crash when I update Neoforge, even though all mods say they support the new version?
A: This typically happens when the environment variables aren’t updated in sync. For example, if `NEOFORGE_VERSION` is set to `20.4.123` but the modloader’s internal `MODLOADER_VERSION` is still `0.20.3`, some mods may fail to initialize. Check the logs for `VersionConflictException` and verify the `version.json` file matches your Neoforge JAR.
Q: Can I manually set environment variables to make older mods work?
A: Yes, but proceed with caution. Use `-Dneoforge.version=20.3` in your launch arguments, but test thoroughly—newer mods may rely on features only available in the latest Neoforge. Avoid hardcoding variables in scripts or config files unless absolutely necessary.
Q: What’s the difference between `NEOFORGE_VERSION` and `MODLOADER_VERSION`?
A: `NEOFORGE_VERSION` refers to the API version (e.g., `20.4`), while `MODLOADER_VERSION` is the internal modloader version (e.g., `0.20.4`). They’re usually aligned, but forks or custom builds may diverge. Always check both in logs if you suspect a version mismatch.
Q: How do I inspect the active environment variables in-game?
A: Use the `-Dneoforge.debug=true` JVM argument. This forces Neoforge to log all environment variables at startup. Alternatively, check the `neoforge.log` file in `.minecraft/logs/` for lines starting with `[NeoForge] Active environment:`.
Q: Are there tools to automate environment variable management?
A: Yes. Tools like Modrinth’s version resolver or FTB’s pack builder handle environment variables automatically. For manual setups, scripts like NeoForge’s Gradle plugin can generate `version.json` files with the correct variables.
Q: What should I do if a mod refuses to load despite correct environment variables?
A: The issue may lie in hardcoded checks. Try: 1. Replacing `System.getenv("NEOFORGE_VERSION")` with `FMLEnvironment.getVersion()` in the mod’s code (if you’re the developer). 2. Contacting the mod author to update their version checks. 3. Using a compatibility layer like MixinExtras if the mod relies on outdated APIs.
Q: Can environment variables be used for mod security?
A: Indirectly. While environment variables themselves aren’t a security feature, Neoforge uses them to enforce sandboxing rules. For example, mods running in a restricted environment (e.g., `-Dneoforge.sandbox=true`) may have limited access to system properties, reducing exploit risks.