Best JVM Arguments for a Modded Minecraft Server

Updated July 28, 2026

For a modded Minecraft server, the proven recipe comes down to three things: the Java version your game version requires (Java 8 up to 1.16.5, Java 17 for 1.18 through 1.20.4, Java 21 for 1.20.5 through 1.21.x, Java 25 from Minecraft 26.1), -Xms and -Xmx set to the same value, and Aikar’s flags — a G1 garbage collector tuning built for Minecraft that has been the community standard since 2018 and remains the best general-purpose baseline in 2026. Generational ZGC only becomes worthwhile on very large allocations, from about 16 GB up.

A lot of folklore orbits that recipe: “magic flag” lists copied from forum to forum, the belief that doubling RAM doubles performance, arguments inherited from Java 8 applied to Java 21. This guide gives the complete flags, explains what they actually do, says when to deviate — and above all how to verify by measurement, with spark, rather than by superstition.

The right Java version comes first

No flag will rescue a server launched on the wrong Java: check this first, and note that the constraint comes from the Minecraft version, not the modpack. Prefer Adoptium’s Temurin builds, free and license-trap-free, and mind both directions: a 1.12.2 pack rejects Java 17 just as surely as a 1.20.5 pack rejects Java 8.

  • Minecraft 1.7.10 through 1.16.5 (RLCraft, GTNH, Create: Above and Beyond…): Java 8 — GregTech: New Horizons is the exception, its modernized 1.7.10 runs on Java 17 to 25.
  • Minecraft 1.17: Java 16, a transition version quickly left behind.
  • Minecraft 1.18 through 1.20.4 (Create Astral, BMC4, Prominence II…): Java 17.
  • Minecraft 1.20.5 through 1.21.x (All The Mods 10, BMC5…): Java 21.
  • Minecraft 26.1 and beyond (the new 2026 version scheme): Java 25.

Aikar’s flags: the baseline that works

Aikar, a developer in the Paper ecosystem, published a set of arguments in 2018 that tunes the G1 garbage collector for Minecraft’s very particular memory profile: enormous numbers of ultra-short-lived objects (one tick creates them, the next throws them away). Untuned, the GC lets that work pile up and then takes big pauses — the familiar periodic freezes where TPS tanks. Aikar’s flags force small, frequent collections that go unnoticed. Written for Paper, they apply just as well to a Forge, NeoForge or Fabric server: a modded server has the same memory behavior, only hungrier.

The full line for a server with 10 GB, to adapt to your allocation: java -Xms10G -Xmx10G -XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 -XX:G1HeapRegionSize=8M -XX:G1ReservePercent=20 -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=5 -XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1 -jar server.jar nogui

The load-bearing pieces: UseG1GC enables the G1 collector; G1NewSizePercent and G1MaxNewSizePercent reserve 30 to 40 percent of the heap for the young generation, where a tick’s objects live and die; MaxGCPauseMillis=200 caps each pause under the length of four ticks; AlwaysPreTouch claims all the RAM at startup instead of on the fly; PerfDisableSharedMem avoids disk-write hiccups; MaxTenuringThreshold=1 discards garbage early instead of copying it from collection to collection. From 12 GB allocated and up, Aikar recommends a variant: G1NewSizePercent=40, G1MaxNewSizePercent=50, G1HeapRegionSize=16M, G1ReservePercent=15 and InitiatingHeapOccupancyPercent=20.

-Xms = -Xmx: why the rule exists

-Xmx sets the JVM’s memory ceiling, -Xms its starting size. On a machine dedicated to the game, set both to the same value: memory you do not give Minecraft serves no one else, and a fixed-size heap spares G1 the busywork of growing and shrinking — combined with AlwaysPreTouch, everything is claimed cleanly at startup. The only exception is a shared machine where other services genuinely need that memory.

Also keep headroom for the operating system: the JVM consumes memory beyond the heap (metadata, threads, mods’ native memory). On a 16 GB machine, allocate 10 to 12 GB, not 15 — a server that pushes the system into swap becomes unplayable far more surely than one running a slightly tight heap.

G1GC or generational ZGC: who actually needs ZGC?

Since Java 21, ZGC has a generational mode — and on recent JDKs, enabling ZGC (-XX:+UseZGC) gives you that mode out of the box. Its promise: sub-millisecond pauses regardless of heap size, where G1, even well tuned, still lets pauses of a few dozen milliseconds through on very large allocations. The price: roughly 10 to 15 percent more CPU spent on GC, plus a small memory overhead.

The practical conclusion is simple. Up to 12 GB of allocation — which covers nearly every modded server — G1 with Aikar’s flags remains the better trade: pauses are already imperceptible and the CPU saved goes back into server ticks. Generational ZGC wins on outlier setups: 16, 24, 32 GB heaps for a big public server on a heavy pack, with CPU cores to spare. If that is you, replace all the G1 flags with -XX:+UseZGC (keeping Xms=Xmx and AlwaysPreTouch) and compare the result under real load with spark — the verdict that counts is measured, not theoretical.

The classic traps

  • Too much RAM: past what you need, every collection churns a bigger heap for nothing. Going from 10 to 20 GB does not speed up a server that only uses 8 — it lengthens the GC’s workload.
  • Magic flags copied without understanding: the exotic lists floating around forums often stack obsolete, contradictory or simply ignored arguments on modern JVMs. A sane, measured baseline beats a mystical pile.
  • Client flags on a server: tweaks meant to raise a modded client’s FPS have no business in a server script, and vice versa.
  • GraalVM as a miracle cure: its JIT compiler can bring a modest gain on some packs, but it is a marginal optimization to try last — after the correct Java version, sound GC flags and profiling out the real lag sources.
  • Changing three things at once: change one parameter, measure for a day, conclude. Otherwise you will never know what did what.

Measure with spark instead of believing

The habit that separates well-run servers from the rest: install spark (Forge, NeoForge, Fabric — free and nearly overhead-free) and look at the numbers before touching flags. /spark tps shows TPS and MSPT (milliseconds per tick), /spark gcmonitor logs every GC pause in real time, /spark profiler produces an interactive report showing exactly where each tick’s time goes.

The reading is unambiguous: if GC pauses are rare and short but MSPT sits above 50 ms, your problem is not the JVM — it is a mob farm, a modded machine or an overloaded chunk, and the profiler will name it. Java arguments eliminate memory hiccups; they do not buy tick time. Set the flags once, correctly, then spend your energy where spark points.

Mods & Tools Mentioned

Frequently Asked Questions

Do Aikar’s flags work on a Forge or NeoForge server?

Yes. They were written for Paper, but they tune the JVM’s garbage collector, not the server software: a modded server has the same memory profile, only more demanding, and benefits just as much. On recent Forge/NeoForge packs, put them in user_jvm_args.txt.

Why set -Xms equal to -Xmx?

A fixed-size heap spares G1 the grow-and-shrink cycles, and with AlwaysPreTouch all the memory is claimed at startup: no allocation micro-stutters mid-game. On a dedicated server, unallocated RAM would sit idle anyway.

Does more RAM make the server faster?

No — past actual need it is the opposite: the GC churns a larger heap for the same work. Size to the pack (6 to 10 GB covers most cases), check real usage with spark, and leave headroom for the operating system.

When should I switch to generational ZGC?

From about 16 GB of heap, on Java 21 or newer, with CPU to spare — typically a big public server on a heavy pack. Below that, G1 with Aikar’s flags already delivers imperceptible pauses at a lower CPU cost. Either way, decide by comparing under real load with spark.

Is GraalVM worth it for a modded server in 2026?

It is a marginal bonus, not a revolution: its JIT compiler can shave a few percent on some packs. Nail the essentials first — correct Java version, sane GC flags, profiled lag sources — and test GraalVM last, with measurements in hand.

How do I tell whether my lag comes from GC or from a mod?

With spark: /spark gcmonitor logs GC pauses, /spark tps shows MSPT. Long, frequent GC pauses point at the JVM — revisit flags and allocation. High MSPT with a quiet GC points at content: run /spark profiler to identify the mod, farm or chunk responsible.

Read Next

Ready to play? Find an active server in the rankings.

See the rankings