"It lags" is what players say the way patients say "it hurts": true, urgent and not yet a diagnosis. This guide turns the complaint into a number, and the number into one targeted change.
The short answer
Minecraft server lag means one of four different problems: ticks that take too long, rare lag spikes, a poor network path or a weak client. Only the first two are the server's job, and one number separates them from the rest: MSPT, the milliseconds the server needs for one tick. The server aims for 20 ticks per second, which leaves 50 ms per tick [1][2]. If your ticks fit into that budget, the complaint lies elsewhere. If they do not, spark, the profiler that Paper has bundled since version 1.21 [7], shows which part of the tick eats the time. Fix the biggest block first, measure again, and think about a bigger server last. Our assessment: more RAM does not shorten a tick that is waiting for the processor, and a spark report tells you whether that is your case [13][18][20].
How it works
- Ticks, TPS and MSPT. Minecraft runs on a loop, and every pass is a tick. In one tick the server handles player packets, moves entities, spawns and steers mobs, processes redstone and sends updates to players [1]. It tries to run exactly 20 ticks per second, one every 50 milliseconds. When a tick finishes early, the server sleeps for the rest of the 50 ms. When a tick runs long, the next one starts late, because ticks cannot run in parallel, and the whole game slows down [1]. TPS (ticks per second) counts how many ticks were completed in a second. MSPT (milliseconds per tick) says how long a tick took. For 20 TPS the average has to stay at or below 50 ms [2]. spark also reports the minimum, the median, the 95th percentile and the maximum, and colours values green, amber or red [2]. In our view MSPT is the better early warning, because TPS stays at 20 as long as the average fits into the budget and only drops once the reserve is gone [2][20].
- Read the numbers.
/spark tpsprints the TPS rate and CPU usage, and spark's guide explains TPS and MSPT together [2][3]. Paper's own/tpsshows the last 1, 5 and 15 minutes, and/msptshows average, minimum and maximum of the last 5, 10 and 60 seconds, but the Paper documentation calls both superseded by spark [8]. On a vanilla server,/tick query(since 1.20.3, permission level 3) prints the ticking status, the average time per tick and percentiles [17]. In the server console you type commands without the leading slash [21]. In game you may need to be an operator or hold thesparkpermission [6]. - Headroom. In a spark profile the tick loop sits near the top, and the time the server spends sleeping is your reserve. spark's guide calls a high sleep share healthy, says that below 20 percent sleep the server works hard and below 5 percent it probably lags with no spare capacity, and reminds you that all of these values are averages [1].
- Profile while the lag happens. Paper's documentation stresses that the problem must be actively occurring, otherwise the profile shows a healthy server [7]. Run
/spark profiler start --timeout 600. After ten minutes spark returns a link to the report [7]./spark profiler infoshows the status,openviews a running profile,stopends it now, andcanceldrops it without uploading [3]. The viewer link can be shared freely [5], so treat it as public. If you would rather keep the data local,/spark profiler stop --save-to-filesaves the profile under the config directory instead of uploading it [3]. Paper 1.21 and newer include spark. On older versions you install the plugin jar, and a newer standalone jar can replace the bundled one if you add-Dpaper.preferSparkPlugin=trueto the startup arguments [6][7]. Paper's Timings profiler is deprecated and off by default since 1.21 [7]. - Read the report. Open the "Server thread" first, the main thread that runs the game [5]. Every line shows the share of the thread's time. Expand the biggest child, then its biggest child, and "follow the numbers" [5]. The viewer also offers a flat view with the 250 slowest method calls, a sources view with one tree per plugin or mod, and a flame graph in which width means time [5]. Because the game's own method names are scrambled, the viewer applies deobfuscation mappings automatically and lets you pick them by hand if that fails [5]. In our reading, three families of names deserve your first look: entities, chunk loading and plugin names.
- Spikes need a different tool. An averaged profile hides rare long ticks, because the normal ticks cancel the spike out [4]. First run
/spark tickmonitor. It reports ticks that took much longer than the average (by default twice as long), and--threshold-tick 50reports every tick above 50 ms [3][4]. Then profile only the long ticks with/spark profiler start --only-ticks-over 100. spark suggests a threshold between 50 and 100 that stays below the length of the laggy ticks you saw [3][4]. Match each tickmonitor message to what happened in game at that moment [4].
Which kind of lag do you have?
This table is our assessment, built from the sources above.
| What players report | Likely kind | First check |
|---|---|---|
| Everything slows down: mobs, redstone, blocks snap back | Tick lag | /spark tps, MSPT above 50 ms |
| Short freezes every few seconds or minutes | Lag spikes | /spark tickmonitor, then --only-ticks-over |
| Actions arrive late, but mobs and redstone run at normal speed | Network path | /spark ping, compare with MSPT [3] |
| One player stutters, everyone else is fine | That player's client or connection | /spark ping --player NAME [3], ask for frame rate |
If TPS sits at 20, MSPT stays well under 50 and the sleep share is high, stop changing the server. The problem is not the tick.
What to change, in this order
Change one thing at a time and measure again under similar load. The order is our judgement, from cheap and safe to invasive, not a measured ranking.
- Chunk generation. When players explore, the server has to generate terrain on the spot, and that shows up as spikes. Chunky generates the area in advance. Its documented commands are
chunky world NAME,chunky center X Zorchunky spawn,chunky radius 5000,chunky start, and thenchunky progress,chunky pauseandchunky continue[14].chunky worldbordercopies the vanilla world border, and the vanilla/worldborder settakes the full width, so a border of 10000 matches a Chunky radius of 5000 [14][21]. The world name depends on your setup, for exampleworldoroverworldfor the Overworld [15]. Hangar lists Chunky 1.5.3 for 26.1 to 26.3 [16]. Run it while the server is empty, because pre-generation is the same heavy work players trigger, only all at once [21]. It costs disk space and backup time, so start with a modest radius [21]. - Distances.
simulation-distanceis the radius in chunks in which the server updates living entities.view-distanceis how much world data is sent to clients. Both default to 10, with a range of 3 to 32 [9]. Lowering the simulation distance reduces the work the server does in each tick, and it is the setting we would try first [20]. Lower it by one or two steps, not to the floor. We found no official recommended value, so treat any number from a forum or a third-party guide as a test value. - Entities.
/paper entity listlists the currently ticking entities, and you can filter by type such asminecraft:pig[8]. Spawn limits live inbukkit.yml(monsters 70 by default) and can be overridden per world [11].per-player-mob-spawnsspreads the mob cap per player [10]. Inspigot.yml,entity-activation-rangedecides how far from a player entities tick normally: 32 blocks for animals and monsters, 64 for raiders, 16 for miscellaneous entities by default [12]. Careful: Paper notes that a small range for miscellaneous entities can make items in water streams look laggy or move backward [12]. Third-party guides name large mob farms, dense villager halls and constant hopper activity as common candidates [20], and your profile shows whether yours is one. - Plugins. The sources view shows the share of time per plugin [5]. Update it, change its configuration, replace it or drop it.
- Autosave. Paper's
max-auto-save-chunks-per-tickdefaults to 24 [10]. If your spikes arrive on a regular beat, look attickmonitortimestamps and at the profile of those ticks before you touch it. We have not tested this setting. - Memory and garbage collection. Java frees unused memory in sweeps called garbage collection (GC), and a long sweep freezes a tick.
/spark gcprints the GC history,/spark gcmonitorreports GC activity as it happens, and/spark health show --memoryadds JVM memory details [3]. Paper's page on startup flags recommends at least 6 to 10 GB, tells you to set the heap about 1000 to 1500 MB below the memory your host gives you, and warns that more memory stops paying off at some point [13]. Other sources give smaller figures for small servers, so check [18] against your own report. All of them agree that more is not automatically better.
When a bigger server helps
A bigger machine is the right answer when the report says the processor is the limit, and only then. The signs, in our reading: the server thread has almost no sleep time, and no single plugin, entity group or chunk source stands out any more after the steps above. Then buy for single-core speed. The Minecraft Wiki says a server mostly uses one core and recommends a CPU with high single-thread performance [18]. Extra cores help plugins and some background work, but the core mechanics such as ticking largely stay on one thread [19]. RAM is a different matter: setupmc.com puts it plainly, more RAM does not shorten CPU-bound tick work [20]. On rented servers, check whether CPU and RAM are guaranteed or shared, because the Wiki lists that as a point to compare [18]. Our guides on hosting criteria, on running a Minecraft server on a VPS and on running one at home cover the buying side.
A worked example (invented values for practice, not a measurement)
Six friends play on a Paper server, and every evening someone says "it lags". During the evening you run:
/spark tps
/spark profiler start --timeout 600Reading A: MSPT averages 22 ms, the 95th percentile is 38 ms, the sleep share in the profile is high. The tick is fine. Check /spark ping, the players' connections and their frame rates before you touch any setting.
Reading B: MSPT averages 58 ms, the sleep share is below 5 percent, and 45 percent of the server thread sits under chunk loading while two friends fly in different directions. Pre-generate with Chunky, shrink the explored area with a border, measure again.
Reading C: MSPT averages 61 ms, sleep is below 5 percent, and after the steps above nothing stands out any more. The server thread is the limit. Now a processor with stronger single-core speed is a justified purchase, and no RAM upgrade will fix it.
After each change, run the same profile again and write both results next to each other. A change that does not move the number goes back.
Checklist
- Measure
/spark tpswhile the lag is happening, and note MSPT, the 95th percentile and CPU usage. - Separate tick lag, lag spikes, network and client before you change anything.
- Start
/spark profiler start --timeout 600during the problem, and open the Server thread first. - Check the sleep share: below 20 percent means the server works hard, below 5 percent means no reserve.
- Run
/spark tickmonitorand--only-ticks-overfor spikes instead of averaged profiles. - Pre-generate explored terrain with Chunky while the server is empty, and set a border first.
- Lower
simulation-distancebeforeview-distance, and change one value at a time. - Look at the sources view before you blame the server, because one plugin can cost most of the tick.
- Compare two reports under similar load, and revert a change that did not help.
- Buy a faster single core, not more RAM, only when the report shows the processor as the limit.