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