Hello!
Server performance in Minecraft depends heavily on both software and hardware configuration. This guide is intended for (semi-)experienced administrators using Spigot, Paper or similar forks (Purpur, Pufferfish…), and covers recent versions 1.20.x to 1.21.x (with notes for older versions where applicable). We will explain the critical settings in configuration files (spigot.yml
, paper.yml
, bukkit.yml
, purpur.yml
, etc.), why default values are often suboptimal, and how tweaking them can improve TPS, CPU load, and server stability. We’ll also give recommendations for performance-oriented plugins, briefly compare the benefits of Purpur/Pufferfish versus Paper/Spigot, and provide advice on Java setup (versions, G1GC JVM flags, etc.). Everything is organized into sections for clear and quick reading.
Choosing Spigot, Paper or an Optimized Fork?
Prefer Paper or its forks over Spigot. Spigot (and its predecessor CraftBukkit) is the historical base, but it now lags behind in terms of performance compared to Paper and its derivatives. Paper is a fork of Spigot that brings many optimizations and fixes while remaining compatible with Spigot/Bukkit plugins. Paper also exposes dozens of advanced configuration options to fine-tune performance without significantly altering gameplay.
Purpur is a fork of Paper geared toward extensive customization. Technically, Purpur includes all of Pufferfish’s optimizations (another fork, see below) but does not add any further unique performance gains. However, it offers hundreds of new “exotic” configuration options to tweak game mechanics (e.g., enabling the ability to ride certain mobs, allowing flying squids, configuring single-player sleep, etc.). By default, these additional Purpur features are disabled, and the server behaves like a standard Paper/Pufferfish setup. Use Purpur only if you need these extra gameplay options, since more patches can mean more potential bugs; if you don’t need them, it’s better to stick with Pufferfish or Paper for maximum stability.
Pufferfish is a fork of Paper focused on pure performance, introduced in 2021. It includes many advanced patches while remaining compatible with the Paper API. Its improvements include, for example: partially asynchronous processing of certain entities, faster mob AI algorithms (DAB system), optimized map rendering via SIMD, more efficient hopper management, optimized ray tracing (line of sight), better memory usage to reduce GC pauses, etc. Most of these optimizations are transparent to gameplay (and those that could have an impact can be disabled in pufferfish.yml
if needed). Additionally, Pufferfish offers “enterprise” features useful to administrators, such as Sentry.io integration to automatically report server errors, and a built-in profiler (Flare) capable of advanced analysis (including memory profiling). In short, Pufferfish aims for maximum performance while staying as close as possible to vanilla behavior. If your goal is to support a large number of players under heavy load, Pufferfish is often the best choice to squeeze out extra TPS percentages. (Note: There’s even a Pufferfish+, an even more optimized version that includes fully asynchronous entity tracking and pathfinding, but it’s a commercial product aimed at very large servers.)
In summary: For most servers, Paper already offers an excellent balance between performance and fidelity to vanilla gameplay. Purpur can be considered if you want greater configuration freedom and some unique features, but without any TPS gain compared to Pufferfish. Pufferfish provides an extra boost in performance and stability that is valuable on heavily populated or demanding servers, without noticeably changing gameplay. On the other hand, avoid obscure or paid “custom” JARs that promise asynchronous miracles – there is a 99% chance they are ineffective or even harmful. Likewise, avoid sticking with a pure Vanilla server or even Spigot if you can switch to Paper: you would benefit from a significant performance improvement just by changing software.
Critical Settings in Configuration Files
Before diving into the details, note that no universal setting guarantees a constant 20 TPS under all circumstances. Every server has its own specifics (world size, number of players, game type, built farms, etc.). The values suggested here are recommended starting points (“good starting value”) based on collective experience, and will need to be adjusted to suit your needs. Optimization often involves making trade-offs: reducing certain distances, frequencies or quantities to ease CPU load, at the cost of slight gameplay changes. It’s up to you to find the right balance between performance and gameplay experience.
We will go through each file and highlight the key options to optimize, explaining the impact of each change. The following sections will cover bukkit.yml, spigot.yml, paper.yml (global and per-world configuration for Paper/Pufferfish), then purpur.yml (settings specific to forks like Purpur). Finally, we’ll also discuss some settings outside configuration files (JVM, OS).
bukkit.yml – Mob Spawn Limits and Frequencies
The bukkit.yml
file mainly manages spawn settings for passive and hostile entities. The default Bukkit/Spigot values are often set quite high, suitable for small, lightly populated servers, but excessive for a survival server with many players. Two categories of settings to adjust:
spawn-limits
: These are the mob quotas allowed to spawn per player. By default, a player can have up to ~70 monsters, 10 animals, 15 water creatures, etc. around them, which with multiple players can quickly overwhelm the server with entities. It is recommended to lower these limits. For example, reasonable starting values are around 20 monsters, 5 animals, 2 water creatures, 1 ambient creature per player. The internal calculation multiplies these limits by the number of connected players, so even with several players, the total remains balanced. By lowering these numbers, you reduce the mob density the server has to manage, easing performance load. Be careful though: this also reduces the wildlife and difficulty of the game. If your server focuses on “hardcore” survival or massive mob farms, don’t go too low or you’ll risk frustrating players. Find a compromise (e.g. ~30 monsters if you want a bit more action). To compensate for the reduction, you can also tweak the spawn radius, see below.
ticks-per:
spawn sections: These settings control the frequency at which the server attempts to spawn new entities. By default, Minecraft tries to spawn monsters every tick (20 times per second) and animals every 400 ticks (~20 seconds). You can slightly slow down these attempts with no visible impact on gameplay, especially for less critical entities. For example, setting monster-spawns
to 2 (instead of 1) means it only tries once every 2 ticks – the difference in spawn rate is imperceptible to players, but the server handles half as many monster spawn cycles. The Paper guide even suggests monster-spawns: 10
ticks, which still feels smooth in most cases. For animals and water creatures, which are not constantly killed in-game, you can radically increase the intervals – for example 400 ticks (20 seconds) or more. This way, the server avoids scanning needlessly every tick for squids or bats that already quickly hit the population cap.
- In summary: increase
ticks-per.*-spawns
(a few hundred for water/ambient fauna, 2 to 10 for monsters) to space out spawn attempts and save CPU time. The impact on gameplay is minimal as long as the population limits (above) remain consistent.
By adjusting spawn-limits
and ticks-per-spawns
together, you can drastically reduce the total number of active mobs to manage while still maintaining a decent experience for each player. Note that Paper offers a very useful option, per-player-mob-spawns
(in paper.yml
), which better distributes spawns between players rather than filling up one player’s quota before moving to the next. By enabling this option (see the Paper section below), you can afford to use lower limits without depriving players of encounters: each player gets their fair share of mobs around them. This setting has a very slight CPU cost, but its benefit to population stability far outweighs that overhead.
spigot.yml – View Distances, Entity Activation and Tracking, Item Management
The spigot.yml
file (used by Spigot, Paper, and forks) contains several key settings to control the activity range of entities and the handling of ground items. The default values aim to match singleplayer behavior, but in multiplayer they can be reduced to save resources:
view-distance
: Spigot allows you to force the chunk render distance, but since Minecraft 1.18+, it is recommended to leave view-distance: default
in spigot.yml and instead use the simulation distance and render distance settings in server.properties
(or via Paper). The simulation distance (simulation-distance
) determines how far out entities and game mechanics remain active, while the view distance (view-distance
) determines how far chunks are visually sent to clients. The optimization trick is to set a fairly low simulation distance (e.g. 4 chunks) while keeping a higher view distance (e.g. 8 chunks or more) – this way, players can see far, but the server only ticks the nearby surroundings. With Paper, the view-distance
in spigot.yml should remain set to “default” to avoid conflicts, and instead set simulation-distance
= 4 and view-distance
= ~7–10 in Paper/server configs. For versions prior to 1.18 that don’t have a separate simulation-distance, the view-distance
in spigot.yml must be lowered directly to improve TPS. For example, reducing from 10 to 6 or 8 chunks exponentially reduces the number of active areas and greatly relieves server load.
mob-spawn-range
: This radius in chunks determines how far from the player mobs can spawn. By default, it’s 8 chunks (128 blocks), which aligns with a view-distance of 8, but you can reduce it to concentrate spawns. A good practice is to set it to 4 or 6 chunks if your simulation distance is low. Make sure that mob-spawn-range
is less than or equal to your effective simulation distance (otherwise the server would try to populate non-simulated chunks). By lowering this radius, you reduce the spawn area, so even with reduced spawn-limits
, it still feels like mobs are always around the player (since they spawn closer). For example, with mob-spawn-range: 3
and a lower monster cap, mobs will concentrate in a smaller perimeter, giving the impression of a lively world while reducing the total number. Adjust this radius depending on game modes: for Skyblock or minigames, you can go very low, whereas for purist PvE you’ll want to stay more moderate. (Versions <1.18: mob-spawn-range
applies the same way.)
entity-activation-range
: This is one of the major levers for performance. It defines the distance (in blocks) at which entities stop being active (their AI is “asleep” as long as no player is nearby). By default, Spigot typically uses ~32 blocks for monsters and animals. These values can often be lowered without noticeable impact, especially for certain categories. For example, recommended ranges are: monsters 24, animals 16, water mobs 8, villagers 16, flying monsters (phantoms) 48, raiders 48, misc 8. In practice, an animal more than 16 blocks away from a player won’t move until the player gets closer, which is harmless for gameplay in most cases. Lowering these ranges eases CPU usage because distant entities no longer consume resources. However, be careful: if you set values too low, certain mechanics may break. For example, iron farms require “active” villagers within a certain radius of zombies; if your villagers' activation range is too low, the iron farm might stop functioning correctly. Likewise, mobs “frozen” until you’re very close can surprise players. We recommend not going below the values listed above unless in extreme cases, and to test critical farms after making changes. Finally, Spigot/Paper also offer a specific option tick-inactive-villagers
to allow villagers to still function outside their range: we suggest disabling it (tick-inactive-villagers: false
), because since 1.14 villagers have a huge impact on tick performance when active in large numbers. Letting them sleep outside the player’s range preserves TPS, at the cost of a distant villager not refreshing trades, or a villager in an iron farm needing a player nearby to “respond.” This is generally an acceptable trade-off given the considerable performance gain observed on 1.14+ servers saturated with villagers.
entity-tracking-range
: This related setting defines how far away entities are sent to the client (visually rendered). It can be larger than the activation range without significant server cost, as it only affects data sent to players. It’s generally advised to keep tracking ranges slightly higher than activation ranges to avoid mobs “popping” suddenly into view. For example, if your animals activate at 16 blocks, you can track them up to ~48 blocks so that players can see them from afar (they’ll just remain static until closer). Values of 48 for most categories (except maybe “misc” entities which can be limited to 32) are a good compromise. Don’t set tracking too low (20–30) or players will see mobs suddenly appear very close to them, which is unpleasant. Keeping the default values (often ~48 for everything except misc) works well in most cases.
merge-radius
: Spigot allows you to configure the distance at which ground items and experience orbs merge with each other. Merging dropped item entities is an excellent way to reduce the number of entities being processed (e.g. instead of 50 separate XP orbs ticking individually, you end up with just one or two larger ones). Default values are generally 4 blocks for items and 6 blocks for XP orbs. You can increase these slightly – for example items: 4 or 5 and xp: 6 – but do so with caution. If the radius is too large, merging could cause unwanted effects: items “teleporting” between blocks to combine, or even phasing through walls. Paper has an option to prevent merging through walls (fix-items-merging-through-walls
); use it if you increase the merge radius significantly. All in all, item merging is preferable to using a cleanup plugin like ClearLagg: it’s native, automatic and more precise (you’re not harshly deleting items, just grouping them). Combined with faster despawning (see below), it helps avoid having too many items lying around.
- Lifespan of Ground Entities: Two essential settings exist in Spigot to prevent the buildup of useless entities:
arrow-despawn-rate
and item-despawn-rate
. By default, an arrow shot by a player stays stuck for 1 minute (1200 ticks) and a dropped item disappears after 5 minutes (6000 ticks). These durations are long and can be safely shortened for better performance: it is recommended to set arrow-despawn-rate
to ~300 ticks (15 seconds) and item-despawn-rate
to ~4000 ticks (~3 minutes). Arrows (especially excess ones from dispensers or skeletons) will be cleaned up faster, avoiding invisible buildup that burdens the server. As for items, 3 minutes instead of 5 is more than enough for a player to pick up their drops; shortening this delay reduces the risk of thousands of forgotten items on the ground taking up tick time. Note: Paper offers a more advanced configuration (alt-item-despawn-rate
) allowing you to set a specific despawn time for certain items (for example, to make “unwanted” items like gravel or dirt disappear faster). If you're using Paper/Purpur, consider enabling this option to target item types that clutter your world (by default, the Paper config sets 15s for common blocks like cobble, netherrack, etc.). This can effectively replace a clearlag plugin: by setting accelerated auto-despawn for farmed items, the server self-regulates without needing a global cleanup command.
nerf-spawner-mobs
: By setting this option to true
, mobs from spawners (dungeon generators, artificial mob farms) will spawn without AI: they don’t move or interact until hit. This may sound drastic, but if your server has a lot of spawner-based farms (zombies, skeletons, etc.), it’s a huge performance gain: these “nerfed” mobs have virtually zero CPU cost. Players can still kill them (they’ll just stand still instead of moving). For survival-focused PvE servers, you might hesitate since it makes spawner exploitation easier (the mobs no longer fight back) – it’s a game design decision. But on servers where economy and farming are a priority, disabling AI for spawner mobs is recommended to prevent 200 zombies waiting in a farm from draining your TPS. Paper even has an associated option (spawner-nerfed-mobs-should-jump
) to allow these motionless mobs to still jump in water (so water systems can move them anyway). In short, if spawners are common on your server, then enable the nerf.
save-user-cache-on-stop-only
: When this option is enabled (true
), the user cache (the .cache
file containing UUID/player data) is saved only when the server stops, rather than continuously. By default, Spigot writes to it regularly while the server is running, which causes frequent disk I/O. By setting save-user-cache-on-stop-only: true
, you slightly improve performance by avoiding these constant writes. Be careful: the downside is that in the event of a crash, unsaved cache data could be lost, potentially causing some players to respawn at spawn or other minor inconveniences (non-critical data). In practice, this risk is minimal if you back up regularly and your server doesn’t crash often. It’s an easy win under normal conditions, especially useful on high-population servers where the player list is constantly changing. Don’t forget to properly stop the server from time to time to flush this cache.
max-tick-time
: Spigot introduces a safeguard system that skips certain processing steps if they take too long during a tick. There are two values: one for tile entities (tickable blocks like chests, hoppers, etc.) and one for mobile entities. By default, each is set to 50 ms. This means that if, for example, your entity processing exceeds 50 ms in a single tick (which is already beyond the normal 50 ms per tick at 20 TPS), Spigot will stop ticking them to avoid worsening the lag. While the intention is good (preventing the server from spiraling into extreme lag), in practice this can cause strange behavior (entities or redstone machines may miss cycles because they’re “skipped”). Many administrators prefer to disable this limiter by setting very high values. For example, setting max-tick-time.tile
and .entity
to 1000 (i.e. 1 second) effectively disables the limit (since it’s rare for a single tick to exceed 1s). Shockbyte suggests 1000 to neutralize the effect. The result: the server will always try to tick everything as expected, even if this leads to TPS < 20. This avoids gameplay inconsistencies caused by skipping. However, keep in mind that if your server actually reaches these thresholds, it’s severely overloaded – raising the limit doesn’t solve lag, it only prevents hiding the issue. We recommend setting 1000 to avoid distorting normal behavior, and addressing the root cause of lag upstream (through other optimizations or by adding resources). Note that Paper has its own crash watchdog that is not affected by these values.
By applying these adjustments in spigot.yml
, you should notice a significant TPS gain in most cases, as it reduces unnecessary distant activity (activation range), prevents the buildup of non-essential entities (quick despawn, merge), and alleviates known bottlenecks (villagers, spawners…). Spigot’s default values are conservative to avoid surprising singleplayer users, but in a server environment they can be greatly improved – which is why hosts like Paper include many of these optimizations by default or recommend them upfront.
paper.yml (Paper & forks) – Advanced Optimization Options
If you're using Paper, Pufferfish or Purpur, you have access to additional configs compared to Spigot. Paper splits its configs into several files (paper-global.yml
, paper-world-defaults.yml
, and per-world overrides). For simplicity, we’ll refer to “paper.yml” to cover the main available options. These are often disabled by default to preserve absolute vanilla behavior, but once enabled they noticeably boost performance without major side effects. Let’s go over the most beneficial ones:
- Game Engine Optimizations:
- Redstone – Paper offers an alternative algorithm called EigenCraft (or Alternate Current) that replaces the vanilla redstone system. Enable
use-faster-eigencraft-redstone: true
(or redstone-implementation: ALTERNATE_CURRENT
depending on the version). This new engine reduces redundant redstone updates and greatly improves performance for complex circuits without changing their observable behavior. Except in ultra-specific cases involving redstone machine bug exploits, there’s virtually no downside to using it – the gain is substantial on servers where redstone farms run continuously.
- Explosions – Set
optimize-explosions
to **true**
to use Paper’s optimized explosion algorithm (TNT, creepers). It calculates affected areas faster, with a negligible loss of precision in damage or physics (invisible to players). Since Minecraft 1.15, Mojang has made some improvements in this area, but Paper’s option remains beneficial, especially if your players enjoy TNT or you use explosion-based mining plugins.
- Anti-Xray – Paper includes an anti-xray system that is much more efficient than traditional plugins. If your survival server is plagued by x-ray cheaters, consider enabling anti-xray in
paper.yml
(anti-xray
set to true, mode engine 2
). This obfuscates undiscovered ore blocks by temporarily replacing their appearance in the chunks sent to players. This feature does have a CPU cost, but it’s far lower than that of an anti-xray plugin that would rescan chunks, and much lower than the impact of traditional x-ray usage on gameplay (since Paper only alters sent data). Note: in very recent versions, Paper’s anti-xray is sometimes disabled by default because Mojang introduced chunk “blending” – check your version’s documentation. In any case, do not use third-party anti-xray plugins on Paper – use the native system.
- Entity and Mob Management:
- Collisions – Limit simultaneous entity collision calculations using
max-entity-collisions
. The default is 8, but 2 collisions per entity is recommended. This way, in a large pile of mobs, each entity will only handle 2 collisions at a time instead of 8, reducing the combinatorial explosion of calculations. A value of 2 is enough for typical cases (even a player will only “bump into” 2 entities at once, which is more than sufficient). Beyond that, it’s just CPU waste to detect multiple collisions that don’t really matter for gameplay. This setting overrides Spigot’s equivalent if you’re on Paper. Note that with max-entity-collisions: 2
, the vanilla gamerule maxEntityCramming
(which by default kills entities when over 24 are stacked) loses some relevance, but that’s not an issue.
- Mobs per Player – As mentioned earlier, enable
per-player-mob-spawns: true
. With this setting, the server will distribute the global mobcap fairly among players, preventing one isolated player from monopolizing all hostile spawns on the server by loading the full 70 possible monsters alone. This makes spawns more consistent and predictable for everyone, similar to singleplayer, and allows you to further reduce spawn-limits
without depriving one player of action if another is sitting in a mob farm. The CPU impact of this extra calculation is very low compared to the overall benefit.
- Hoppers – Hoppers are known to be one of the worst enemies of TPS, as they perform constant checks by default (every tick) to see if they can pull or push items. Paper offers several optimizations:
- Set
hopper.disable-move-event: true
only if you use no plugin that listens to the inventory event InventoryMoveItemEvent
(typically protection or item log plugins). By disabling it, you prevent the server from creating an event for every item moved through a hopper – which is a massive performance gain on servers full of sorting or storage systems. However, if you use plugins like Lockette, chest protection, or others that depend on these events, do not enable this or they may no longer work properly.
- Increase hopper operation delay: in
spigot.yml
, you have hopper-transfer
(default 8, which means 8 ticks between each item transfer, or 2.5 items per second) and hopper-check
(default 1, which means scanning every tick to check for an item above). By setting hopper-transfer
to 8 (the default value, which you can keep) and hopper-check
to 8 (instead of 1), your hoppers will only check 2.5 times per second for an item to pull above instead of 20 times/sec. This greatly reduces server load if you have floors covered in hoppers, but it may break certain ultra-fast redstone clocks using comparators on hoppers. A value of 8 ticks is a commonly recommended compromise; it slightly slows the responsiveness of some hopper-based systems but remains fast enough for most item sorters (which are often tuned to 8 ticks anyway due to hoppers' internal cooldown mechanic). Tip: Test your sorters and item farms after this change, and adjust if needed (e.g. 4 ticks if 8 causes issues, or more than 8 if you're prioritizing TPS at all costs).
hopper.ignore-occluding-blocks: true
– this option makes hoppers ignore containers through a solid block (e.g. a hopper minecart buried under sand). By setting it to true, you disable a fairly niche vanilla behavior that isn’t commonly used in standard survival, and gain a bit of performance on hopper checks. However, it can break certain creative farms that rely on this mechanic – only enable it if you’re sure this kind of glitch isn’t used on your server.
- Villagers – Paper/Purpur include several optimizations for villagers, who are known to be very resource-intensive in 1.14+ due to their complex AI (looking for beds, jobs, paths…). In addition to
tick-inactive-villagers: false
already mentioned, Purpur offers villager.lobotomize: true
, which removes AI from villagers too far from their goal. In short, if a villager is running in circles because he can’t reach his bed or workstation, the server will “lobotomize” him (he stops aimlessly searching) until a player frees or approaches him again. The lobotomized villager won’t do much except restock trades occasionally. Only enable this in case of severe lag due to villagers, otherwise you risk reducing normal village activity. Similarly, Purpur allows you to reduce the search radius villagers use to find a bed or point of interest (villager.search-radius.acquire-poi
, etc.) – setting them to 16 blocks, for example, greatly improves performance in a massive village, at the cost of villagers no longer “seeing” distant beds or jobs. These settings can be useful if your players have built massive trading halls or villager-based farms.
- Monsters and Others – Purpur offers small extras like
zombie.aggressive-towards-villager-when-lagging: false
(so during lag, zombies stop chasing villagers, which can ease server load during a spike). It’s not critical but serves as a temporary relief during low TPS. Similarly, entities-can-use-portals: false
disables entities (other than players) from using Nether portals. This prevents mobs from accidentally loading other dimensions in a loop (a large zombified pigman walking through a lit portal would force the server to load a Nether chunk, which is costly). By disabling this, you gain stability (no more massive pigmen squads showing up at Nether spawn or causing unnecessary chunk loads). It’s a small gameplay trade-off (animals/monsters will no longer travel between the Overworld and Nether/End) for a noticeable stability gain on public servers.
- Chunk & World Loading:
prevent-moving-into-unloaded-chunks: true
– You should absolutely enable this option on Paper/Pufferfish. It prevents a player moving too fast (e.g. with elytra) from entering a chunk that hasn't yet been generated/loaded, which would trigger a very costly synchronous load that can freeze the server. With this setting enabled, the player will be held at the edge until the chunk is cleanly loaded in the background, preventing heavy lag. This is especially useful if you’ve lowered the view distance: the lower it is, the higher the chance a fast-moving player will reach and cross the loading boundary. This safeguard noticeably improves stability.
delay-chunk-unloads-by
– Paper allows you to delay chunk unloading when a player moves away. By default, setting a delay of 10s is a good choice. This way, if a player quickly goes back and forth or circles around, the server won’t constantly load/unload the same chunks every few seconds – it keeps them in memory for a short time. This avoids repeated IO/CPU operations. Of course, don’t set the delay too high either, or you’ll keep too many unnecessary chunks loaded (increased memory usage). Around 10 seconds is a well-accepted compromise in the community. If you have areas that are frequently visited via teleportation (spawn, etc.), it may be wise to use a plugin or command to force certain chunks to stay always loaded (rather than relying on a delay).
- World Pregen – Pre-generating the world can eliminate major lag spikes caused by in-game chunk generation. However, since version 1.18+, Mojang has optimized terrain generation and asynchronous loading, so pregeneration is no longer essential unless you’re on a very slow CPU or heavily limited server. If you’re hosting on a powerful machine, exploring new chunks should no longer cause TPS drops (it may only slow down terrain loading on the player’s end if the CPU is saturated). That said, for server launches or stagnant worlds, you can define a border and use a plugin like Chunky to pre-generate everything within that boundary. This ensures that no heavy generation occurs during gameplay (everything is already prepared on disk) – note that the pregeneration process itself is long and intensive, so plan it during maintenance. Tip: set a worldborder for each of your worlds (Overworld, Nether, End) to prevent players from endlessly generating unnecessary terrain. A border in the Nether should be 8x smaller proportionally (due to the Nether’s scale). And if you enable treasure maps (see below), a border is necessary to avoid infinite lag from treasure searches beyond the limits.
- Treasure Maps and Exploration – A commonly overlooked point: treasure maps (found in shipwrecks or sold by cartographer villagers) can cause huge lag spikes if they search for very distant structures. By default, Minecraft always tries to generate a map pointing to a new undiscovered structure, which may require loading thousands of new chunks to find an ocean monument or woodland mansion. Paper has an option
treasure-maps.enabled
– set it to false to completely disable treasure maps if you don’t care about them (no lag, but no maps either). Otherwise, at minimum, set treasure-maps.find-already-discovered: true
(for loot and trades), which allows maps to point to already generated/discovered structures instead of always seeking new ones. This way, a player farming treasure maps won’t crash the server by exploring 10 new ocean regions per map – they’ll be sent to known locations instead. Important: if you want to keep maps enabled, make sure to have a worldborder and ideally pre-generate the inside of it, because even with the setting above, the first discovery of a structure can still hit hard.
We’ve just covered the most essential Paper/Purpur options. These allow you to shave off every millisecond: by optimizing redstone, collisions, hoppers, etc., you eliminate countless micro-lags that, combined, significantly improve TPS stability. In fact, Paper already enables some of these by default (for example, sync-chunk-writes
is forced to false on Paper so that chunk writing is asynchronous, whereas on Vanilla/Spigot you must set it manually in server.properties). Finally, remember that Purpur does not add any further technical optimizations – it builds on Pufferfish/Paper for that. What it offers are optional tweaks (for example, the alternate keepalive system to avoid timeouts for slow players, or disabling certain mechanics as mentioned earlier). It’s up to you to pick from these options based on the specific issues you’re facing (e.g. many players getting kicked for Timed Out? Try Purpur’s use-alternate-keepalive: true
).
Performance Plugins and Management Tools
Beyond configuration, some plugins can help diagnose or mitigate performance issues. Here’s a selection of proven tools that have a real impact on server smoothness or administration:
- Spark – Essential for anyone who wants to profile their server. Spark is a plugin that lets you record real-time CPU and memory performance profiles of your server. By running the command
/spark profiler
for a few seconds, then /spark profiler --stop
, you get a detailed report on what is consuming CPU time (tasks, entities, plugins, etc.) or memory. It also includes a convenient web viewer. It’s the perfect tool for identifying the cause of your lag spikes (for example, discovering that a certain mob type or plugin function is taking up 40% of tick time). Spark also provides commands like /spark tps
, /spark health
, and even /spark profiler --memory
to track possible memory leaks. In short: use Spark if you're facing unexplained TPS issues – it’s the most complete and lightweight profiler for Minecraft.
- Timings (built into Paper/Spigot) – It’s not a plugin, but it’s worth mentioning. The command
/timings report
(or /timings paste
) generates a report of the heaviest tasks on your server since the last timings reset. Paper significantly improves the Timings tool compared to Spigot, providing load graphs and detailed breakdowns of events, functions, and even costly entities. Make sure to use it regularly to guide your optimizations: for example, timings might show that chunk management takes up 40% of the tick (a sign you should lower view-distance or pregen), or that a shop plugin is using too many resources, etc. Combined with Spark for deeper analysis, it’s your performance dashboard.
- FarmLimiter / FarmControl – This type of plugin monitors and limits the size of entity groupings (mobs or animals) in AFK farms. A common issue on survival servers: players build massive mob or animal farms (e.g. 500 cows crammed into a tiny pen, or monster “stacks” in a water corner). Even with spawn-limits configured, such concentrations can still occur through breeding or spawners. FarmLimiter (or its modern successor FarmControl) lets you, for example, set a rule that beyond 30 mobs of the same type in a given radius, new spawns are blocked or excess mobs are gradually removed. It’s a preventive way to contain abuses that destroy TPS. A good plugin of this kind will distinguish between natural mobs and those from spawners, and act gently (e.g. prevent breeding when the limit is reached, rather than slaughtering your animals). Note: With Paper, you can already limit some behaviors (e.g. the rule
max-entity-collisions: 2
and the cram rule prevent 500 entities from stacking physically), but FarmControl goes further by handling a variety of scenarios (too many mobs around a player, item accumulation in farms, etc.). If your community enjoys extreme farms, it’s a welcome addition.
- ClearLag(g) – An old but well-known plugin, it periodically cleans up ground entities, excess mobs, etc., through scheduled tasks and commands (e.g. message “Clearing in 60 sec” followed by item removal). Opinion: ClearLag can temporarily fix overload (it “trashes” everything lying around), but it’s more of a bandage than a sustainable solution. Often, properly configuring item despawn and merging makes ClearLag unnecessary. Additionally, ClearLag itself consumes resources to scan all entities regularly. If your base configuration is solid (as detailed above), you shouldn’t need this plugin. It’s mentioned here because many use it out of habit. Prefer native solutions (merge, alt-despawn) or targeted ones (FarmLimiter for mobs). That said, ClearLag can still be useful for its other features: it can dynamically limit hostile mob spawn distance based on TPS, trigger item cleanup if a chunk exceeds X entities, etc. If you install it, use it more as a safety net than a main crutch.
- VillagerOptimizer – If your villagers are still a problem (e.g. villages with 100+ villagers causing lag), you can try this plugin. It reduces how frequently villagers perform certain expensive tasks (bed searching, pathfinding). Essentially, it “slows down” their brains so they don’t hit the server 20 times per second each. This is similar to Purpur’s settings for villager tick rates, but available as a plugin for Spigot/Paper as well. Some similar plugins also offer the ability to disable infinite trade stock regeneration (to prevent trade farms from running endlessly). Before using this kind of plugin, make sure you’ve already set
tick-inactive-villagers: false
and optionally reduced villager.tick-rate
via Paper (Paper/Purpur include a tick-rates
section where you can space out certain villager checks). Often that’s enough. VillagerOptimizer is mainly useful on Spigot, which lacks these native optimizations.
- Chunky – World pregeneration plugin. As mentioned earlier, pre-generating your maps can eliminate exploration-related lag. Chunky is a simple and efficient tool for that: you define a radius or borders, and it gradually fills in all chunks within those limits. It runs asynchronously so it won’t crash your server during the operation, but plan to do it during off-peak hours. Once done, you can uninstall the plugin. It’s useful at server launch or if you add a new world/dimension and want to prepare for player exploration. Keep in mind that with Paper and beyond, asynchronous chunk loading is optimized: in theory, an explorer no longer causes a dramatic TPS drop – it may just slow down their own chunk loading if moving too fast. So pregeneration is a comfort improvement, but not an absolute necessity on recent versions unless in specific contexts (low-end hardware or Dynmap needs).
- Lag Analysis Plugins – In addition to Spark, also consider TickTools, LagMonitor, or Minebench. These are plugins that monitor your TPS, memory, and sometimes log long events (>50ms). For example, LagMonitor can alert you when a plugin triggers a 200ms Garbage Collection, etc. Useful for proactive administrators, but not essential. Paper already includes
/mspt
to view the average time per tick, and its timings are often sufficient.
Of course, there are other performance-focused plugins (e.g. NoMobLag, which dynamically adjusts spawns based on TPS, LimitPillagers, which limits the influx of pillagers around outposts, etc.). Choose tools based on the issues you observe. Avoid miracle plugins that promise to “multithread” the server or magically optimize without tradeoffs – 99% of the time they’re ineffective or worse, dangerous. Serious solutions are those that target a specific aspect (profiling, mob limitation, etc.) or that leverage mechanisms provided by Paper.
To close out on plugins, a reminder: do not hot-reload your plugins in production. Commands like /reload
or plugins that allow loading/unloading without restarting are known to cause memory leaks, inconsistencies, and crashes. Always prefer a clean server restart after adding or removing plugins. This ensures long-term stability.
Java Environment Configuration (JVM, Hardware)
Optimizing Minecraft doesn’t stop at game configuration: the Java runtime environment and allocated resources also matter.
Java Version: Make sure you're using an up-to-date and supported Java version. Since Minecraft 1.18, the minimum is Java 17, and for Minecraft 1.20.5+ you need Java 21 or higher. Avoid Java 8 or 11 on modern servers – not only are they no longer supported by the latest versions of MC, but improvements in the language and garbage collector in Java 17/21 provide significant gains in performance and stability.
Garbage Collector (GC): Minecraft servers use memory intensively, generating a lot of “garbage” (temporary objects). Poor GC tuning can cause pause times of several hundred milliseconds (causing stutter/low TPS). Fortunately, Java 17+ uses the G1GC garbage collector by default, which is well suited to MC-style loads. However, it's recommended to tune the JVM flags for G1GC with server use in mind. The community often recommends the “Aikar flags”, named after a Paper developer who popularized an optimized JVM configuration. These flags aim to reduce pauses and smooth out GC behavior. Rather than listing them here (as they evolve over time), the best option is to use an updated flag generator. For example, the site flags.sh
automatically provides the correct command line based on your Java version and desired RAM allocation. Paper’s guides also point to official documentation and the Spigot Optimization Guide for recommended flags. As a general rule, follow these principles:
- Allocate enough RAM: Too little memory (<4 GB) will force the GC to run constantly. But don’t over-allocate either (avoid setting 32 GB “just because”), as G1 works better with a manageable heap it can clean regularly. For a typical 50-player non-modded server, 8 GB is usually sufficient. Adjust as needed (monitor usage via Spark or timings if possible).
- Set Xms = Xmx: This is standard advice – set the same value for both the minimum and maximum heap (e.g.
-Xms8G -Xmx8G
). This way, the JVM allocates all memory upfront and doesn’t need to resize the heap dynamically, avoiding unnecessary delays during runtime.
- Use G1GC: On Java 17+, this is already the default GC. Recommended G1 flags often include:
-XX:MaxGCPauseMillis=200
(target max pause ~200ms, adjust as needed), -XX:+ParallelRefProcEnabled
(speeds up reference cleanup), -XX:+AlwaysPreTouch
(pre-allocates memory to avoid later slowdowns), -XX:G1NewSizePercent=30
, etc. Rather than explaining each one, rely on the flag bundle provided by Aikar or the generator – they’re proven and reliable. Warning: Some very old flags (e.g. UseConcMarkSweepGC
or UseParallelOldGC
) are obsolete or counterproductive – don’t use them on recent Java versions.
- Monitor GC activity: Even with good flags, keep an eye on GC behavior. The
/spark gc
command or certain timings can show you the % of time spent in GC. Ideally, this should remain low (<5%). If you observe frequent stop-the-world events, you may need to adjust (increase RAM or investigate a potential memory leak).
- Alternative JVMs: While JVMs like OpenJ9 or GraalVM exist, Paper and Spigot do not officially support them, and they may cause unpredictable issues. Their benefit on a Minecraft server is unproven in most cases, especially compared to the stability and maturity of G1GC.
Other System Tips:
- CPU: Minecraft is essentially single-threaded (except for certain backend tasks). Processor frequency and IPC matter more than core count. On a dedicated server or VM, prioritize fewer but faster cores. That’s exactly why we offer MyBoxPerf!
- I/O and Disk: With Paper, many disk operations (chunk saving) are async, but a slow disk can still become a bottleneck. Use an SSD/NVMe for world storage if possible. Here again, MyBox and MyBoxPerf plans have you covered.
- Network: Indirectly related to performance, the
network-compression-threshold
setting (in server.properties) can be adjusted. By default set to 256 bytes, meaning packets under 256 bytes are not compressed. On real player internet connections, keep 256 or raise to 512 if you want to reduce CPU load at the cost of a few extra KB per packet. Network compression has little impact on TPS in general, except on crowded servers (100+ players) where it becomes more noticeable.
In short, keep your Java environment up to date and optimized: a good Java version, the right flags, enough memory, and a fast CPU are the foundation your configuration optimizations can truly shine on.
Conclusion and Final Tips
By applying the recommendations in this guide, you should end up with a much more stable and performant server, capable of maintaining 20 TPS in many situations where the default setup would have struggled. To recap a few key points:
- Use a performant engine: Switch to Paper or an optimized fork instead of Spigot; take advantage of proven performance patches.
- Tune your configs: Reduce simulation distances, spawn limits, despawn times, and activation ranges to eliminate unnecessary processing. Enable Paper optimization options (alternate redstone engine, reduced collisions, anti-xray, etc.) to gain on all fronts.
- Monitor constantly: Use Spark to identify sources of lag. Optimization is an ongoing process – every new farm built or plugin added can introduce a weak point. Respond accordingly by adjusting configs or adding a control plugin (FarmLimiter, etc.) if needed.
- Enforce limits: Don’t let players do whatever they want at the server’s expense. Clearly communicate your entity rules (e.g. “no more than 50 mobs per chunk”) and use tools to enforce them automatically if necessary. Your players would rather have a soft cap on their farms than play on a server crawling at 5 TPS.
- Be ready to compromise: A server that is 100% vanilla in behavior and 100% smooth under heavy load doesn’t exist. Pick your battles: is it better to have slightly “dumber” villagers or a 200-villager spawn that paralyzes the server? The answer is clear. Communicate with your players about these adjustments – most will understand that a small individual sacrifice improves the collective experience.
- Update smartly: Keep your software (Paper, Purpur…) up to date – they often include new optimizations or performance fixes. Read the changelogs. Likewise, stay informed on developments (e.g. Folia, a future multi-threaded server from Paper, promises interesting gains under certain conditions – one to watch when stable). Don’t miss out on easy improvements just out of habit or conservatism.
Finally, remember that every server is unique. This guide gives you a solid foundation, but it’s up to you to fine-tune it: test changes gradually (ideally one at a time to observe their effects), measure impact via /timings
or Spark profilers, and adjust accordingly. Get your moderators or trusted players involved to spot any side effects (a farm working less efficiently, etc.). Optimization is a balance between performance, stability, and gameplay — by following the advice here and staying attentive, you’ll find that balance, and your server will be all the better for it.
Happy tuning, and enjoy smooth, optimized gameplay!
Sources: Optimization guide by YouHaveTrouble, documentation, official Paper/Purpur guides, and community experience.