
Twenty TPS is the ceiling for a Minecraft server: the game runs 20 ticks per second, one every 50 milliseconds. On a small vanilla server you hit it without trying. On a 30-player ATM10 server with a few hundred mods, holding it takes work, and the only way to know whether you are there is to measure your own server.
What your server holds depends on your pack, your world and what your players do, so this post is about the method: how to set up a test you can repeat, what to record, and how to tell whether a change helped.
TPS and MSPT, and why MSPT matters more
MSPT is milliseconds per tick, the time the server needs to finish one tick. The budget is 50 ms. As long as the average tick fits inside that budget, TPS reads 20. Once the average goes past 50 ms, the server can no longer keep up and TPS drops to roughly 1000 divided by MSPT: 60 ms per tick gives about 16.7 TPS, 80 ms gives 12.5.
That is why MSPT is the number to watch. TPS only moves once you have already run out of headroom. MSPT shows you the headroom itself: a server averaging 45 ms is at 20 TPS today and one busy mob farm away from lag. If TPS sits below 20 while the typical tick time looks fine, look at the worst ticks rather than the middle ones. A handful of very long ticks, a long garbage collection pause or a slow autosave for example, can make the server skip ticks without moving the median much. The 95th percentile and max columns in /spark tps show them, and so does /spark tickmonitor --threshold-tick 50, which reports every tick over budget. Also compare the same time window: /spark tps gives TPS for the last 5 seconds up to the last 15 minutes, but tick durations only for the last 10 seconds and the last minute.
Set up a test you can repeat
A single reading during a busy evening tells you little. You want the same conditions each time, so that the only thing that changes is the setting you are testing.
- Make a copy of the world and keep it as your test world. Restore it before every run, so each test starts from the same state.
- Write down the fixed setup: pack name and version, loader version (NeoForge, Forge or Fabric), Java version,
-Xmx, garbage collector flags,view-distanceandsimulation-distance. - Pre-generate the area your players use, so chunk generation does not end up in your numbers. Our Chunky pre-generation guide covers that.
- Use real play if you can. Bot tools that log in fake players are tempting, but most of them do not build farms, run machines or open mod menus, and in a modded pack that is where the tick time goes. A one-hour session with your own group, doing what they normally do, is a better load than a hundred idle bots.
Measure with spark
spark runs on NeoForge, Forge, Fabric and Paper (Paper has shipped it built in since 1.21, according to the PaperMC docs). Three commands cover most of what you need:
/spark tps
/spark health
/spark profiler start --timeout 600
/spark tps prints the server's TPS and tick durations. /spark health adds CPU, memory and disk use. The profiler samples for ten minutes, stops on its own and gives you a link to a report that shows which mods, block entities and entities used the tick time. If you only care about the bad moments, add --only-ticks-over 50 so it records only ticks that went over budget. The flags are listed in the spark command reference.
Keep a small log for every run. A plain table is enough:
| Run | Change | Players online | Median MSPT | 95th percentile MSPT | Worst tick | Profiler link | What players were doing |
|---|---|---|---|---|---|---|---|
| 1 | none (baseline) | ||||||
| 2 | simulation-distance 10 to 6 |
Fill it from the spark output of each run. The 95th percentile is the useful column: it tells you how bad the slow ticks get, which is what players actually feel.
Where modded tick time usually goes
The profiler groups the work, and in modded packs the same few groups come up again and again:
- Block entities: machines, pipes, storage networks, anything that ticks in place. Big AE2 or Mekanism setups show up here.
- Entities: mob farms, dropped items, mobs added by content mods.
- Chunk loading and generation: players exploring, and chunk loaders keeping areas active.
- World ticking: random ticks for crops and leaves, weather, lighting.
Fix the biggest entry first. It is often one build or one mod, not the pack as a whole.
Settings worth testing, one at a time
Change one thing per run, restore the test world, repeat the same session and compare the log.
simulation-distanceinserver.propertiessets how far from each player the world is actually ticked. Lowering it while keepingview-distancewhere it is keeps the scenery but cuts the ticked area. Farms and machines outside the range stop running while nobody is near them, so tell your players.- The garbage collector. G1 with Aikar's flags is the usual default; ZGC can remove GC pauses on large heaps. Check
/spark gcfirst: if GC pauses do not line up with your lag, switching collectors will not help. Our ZGC vs G1GC guide has the flags for Java 21 and Java 25. - Mod features you do not use. Many content mods let you switch modules off in their config files. Fewer active features means less to tick.
- Chunk loaders. Claim mods such as FTB Chunks let you cap how many chunks each player can keep loaded. A handful of always-loaded bases can cost more than the players who are actually online.
- Random tick speed. On versions before 1.21.11 the game rule is
randomTickSpeed, from 1.21.11 it israndom_tick_speed(Minecraft Wiki). Lowering it slows crop growth and leaf decay for everyone, so it is a last resort.
How many players can a modded server hold?
We do not publish a player cap per pack, because the answer depends more on what your players build than on how many of them there are. Ten players with automated bases can load a server harder than thirty who mostly explore. Start with the RAM the pack's own page asks for, run the test above with your group, and look at the 95th percentile MSPT. If it stays comfortably under 50 ms with your usual crowd online, you have room.
Hardware still sets the ceiling
Most of the tick work in Minecraft, NeoForge and Fabric runs on one main server thread, so single-core speed matters more than core count. On Space-Node the CPU depends on the location and tier you pick: Premium in the Netherlands, Germany, Poland and Canada runs on an AMD Ryzen 9 9950X with DDR5, Standard is an AMD EPYC 7443 with DDR4 in the Netherlands, Germany and Poland and Ryzen 9 3900X-class with DDR4 in Canada and India, the two USA locations use a Ryzen 9 7950X3D, and Singapore and Australia use a Ryzen 9 5950X. The plan selector shows the CPU for each location before you order.
Hardware gives you the ceiling. The test above tells you how close your pack gets to it.