Minehost
Home/Blog/Minecraft server optimisation: paper.yml, spigot.yml and bukkit.yml from scratch

Minecraft server optimisation: paper.yml, spigot.yml and bukkit.yml from scratch

12 min readMineHost Team

Most Minecraft optimisation guides tell you to paste fifty lines into paper.yml. The trouble is that this file has not existed since 1.19, because Paper split it into two separate files inside the config directory. Below we go through which settings in server.properties, spigot.yml, bukkit.yml and the Paper files actually change performance, what values to put in, and what each change costs you, because every one of them takes something away in return.

The short answer: six changes that do the heavy lifting

If you are only going to change a handful of things, change these. They account for the vast majority of the real gain on a typical plugin server, and their side effects are predictable.

SettingFileDefaultRecommendedWhat you gain
view-distanceserver.properties106 to 8The single biggest win. Fewer chunks to send and keep in memory.
simulation-distanceserver.properties104 to 6Fewer ticking mobs and mechanisms. Usually relieves the CPU more than view-distance does.
max-entity-collisionspaper-world-defaults.yml82A lifesaver on servers with farms and tightly packed mob herds.
redstone-implementationpaper-world-defaults.ymlVANILLAALTERNATE_CURRENTFar faster redstone with identical behaviour in most builds.
mob-spawn-rangespigot.yml84 to 6Mobs spawn closer to the player, so fewer of them despawn for nothing.
hopper.disable-move-eventpaper-world-defaults.ymlfalsetrueRemoves an enormous number of hopper events from the CPU. Only when no plugin listens for them.
Defaults differ between Minecraft versions and Paper builds. Always check what is actually in your file instead of assuming.

One change at a time

Pasting an entire ready-made config at once means that when something breaks, you have no idea which line did it. Change one thing, restart, give the server fifteen minutes of normal traffic, and only then judge.

Before you change anything, measure what actually hurts

Optimising without measuring is guessing. Your server may be choking on a single badly written plugin while you spend a week lowering the view distance and wondering why nothing helps. Three tools tell you almost everything.

  1. 1

    /tps, or whether the server is keeping up at all

    20 TPS is both healthy and the ceiling, it will never go higher. A drop to 18 is already noticeable, and below 15 the game starts stuttering on every hit and every chest you open. Paper shows three numbers: the average over one, five and fifteen minutes.
  2. 2

    /mspt, or how many milliseconds one tick takes

    This number matters more than TPS. The server has 50 ms per tick. If you fit into 30 ms, you have headroom. At 45 ms the TPS still reads 20, but you are half a step from dropping, which is exactly why a server only starts lagging once two more players join.
  3. 3

    spark, or what is actually eating those milliseconds

    Paper retired the old Timings mechanism in favour of spark, and spark is the right tool today. Run /spark profiler start at peak hours, give it a few minutes, stop it and open the report. You get a call tree with plugin names and percentages of time. Without it you are fixing blind.

What such a measurement usually reveals

It very often turns out that the lag comes from one plugin doing something heavy on the main thread, from world generation in front of a player flying on an elytra, or from a farm nobody is keeping an eye on. None of those is fixed by configuration.

Where these files actually live (and why paper.yml is gone)

Since Minecraft 1.19 Paper no longer uses a single paper.yml, because its contents were split into config/paper-global.yml for server-wide settings and config/paper-world-defaults.yml for world settings. The migration happens automatically on first start, but every guide written before that change sends you to a place that no longer exists.

FileWhat it controlsStill current
server.propertiesGame settings from Mojang itself: distances, limits, networking.Yes, and the two most important settings live here.
bukkit.ymlMob spawn limits and how often spawning is attempted.Yes. Rarely touched, occasionally necessary.
spigot.ymlEntity tracking ranges, item merging, hoppers, projectile despawn.Yes.
paper.ymlThe former single configuration file of Paper.No. Gone since 1.19, stop looking for it.
config/paper-global.ymlGlobal things: redstone, IO threads, player auto-save, packet limits.Yes, one of the two halves of the old paper.yml.
config/paper-world-defaults.ymlCollisions, mob despawn, tick rates, explosion optimisation, hoppers.Yes, the other half and the richest source of real gains.
The Spigot and Bukkit files sit in the server root, the Paper files in the config subdirectory.

Per-world settings

paper-world-defaults.yml holds the defaults for every world. If you want different settings for world_nether only, you create a paper-world.yml inside the directory of that world and override the keys you need. In spigot.yml the same job is done by adding the world name next to default under world-settings.

server.properties: two settings that matter more than all the rest

If you are going to change exactly one thing on the whole server, lower simulation-distance. It decides how far from a player the server calculates mobs, crop growth, redstone and mechanisms, which means how much work the processor does on every single tick.

server.properties
view-distance=7
simulation-distance=5
entity-broadcast-range-percentage=75
network-compression-threshold=256
sync-chunk-writes=false
max-tick-time=60000
  • view-distance is the radius in chunks the server sends to the client. Going from 10 to 7 cuts the number of chunks per player by nearly half. Players mostly notice it in long-distance views, so on a survival server 7 is practically imperceptible, while on a server built around scenic maps it is rather more visible.
  • simulation-distance is the radius in which anything happens at all. A value of 5 means a farm six chunks from the player stops. For most servers that is a feature, but for a technical server with AFK farms it is a serious mechanical change you need to announce.
  • entity-broadcast-range-percentage scales the distance from which a client receives entity updates. 75 percent cuts network traffic and client-side work, which helps most on servers with a crowd at spawn.
  • sync-chunk-writes=false lets chunks be written asynchronously and removes the noticeable stutter on autosave. The risk of losing a few seconds of the world if the process is killed hard is real, but acceptable when your backups work.
  • Leave network-compression-threshold at 256 unless the server sits behind a proxy on the same machine. Then -1 disables compression and saves CPU, because the traffic never leaves localhost. Over the internet, disabling compression will noticeably increase bandwidth.

max-tick-time=-1 is not an optimisation

Setting -1 disables the watchdog, the mechanism that kills a hung server. It speeds up nothing, and all it really does is ensure that instead of a clean crash with a full stack trace you get a server hanging for hours with no trace of what blocked it. Leave the default 60000.

spigot.yml: entity ranges, item merging and hoppers

In spigot.yml the biggest gains come from shortening entity tracking ranges and merging dropped items more aggressively, because both reduce the number of objects the server has to remember and broadcast to clients. Everything below goes under world-settings: default:.

spigot.yml, the world-settings: default section
entity-tracking-range:
  players: 48
  animals: 32
  monsters: 32
  misc: 24
  other: 48
  display: 128
merge-radius:
  item: 3.5
  exp: 6.0
mob-spawn-range: 5
item-despawn-rate: 4000
arrow-despawn-rate: 600
hopper-transfer: 8
hopper-check: 8
hopper-amount: 3
nerf-spawner-mobs: true
save-user-cache-on-stop-only: true
ChangeGainCost to the player
entity-tracking-rangeThe defaults are 128 for players and 96 for mobs, so dropping to 48 and 32 cuts a genuinely large number of packets and tracked entities per player.Animals and mobs appear on screen slightly later, from closer up.
merge-radiusThe defaults are 0.5 for items and disabled for experience, so 3.5 and 6.0 merge stacks that would otherwise lie around in the hundreds.At high values items visibly jump together after mining, which some players notice.
mob-spawn-rangeMobs spawn within reach of the player instead of dying off immediately after spawning.Less spawn variety at distance, which mob-farm servers will feel.
item-despawn-rateAbandoned items disappear sooner, so fewer entities stay around.4000 ticks is about 3 minutes instead of 5. A player who died and did not make it back loses their gear.
nerf-spawner-mobsMobs from spawners have no AI, so no pathfinding is calculated.Farms based on spawners and pushing mobs with water stop working.
hopper-checkHoppers check their surroundings less often, a big relief for large sorting systems.Item transport is noticeably slower. With hopper-amount: 3 this balances out almost entirely.
Every one of these changes has a cost the player can see. It is worth knowing what you are trading away.

max-tick-time: a waste of time on Paper

The max-tick-time section with its tile and entity keys is sometimes recommended in old guides as a cure for lag. On Paper it does nothing at all, because the engine disables those options with its own patches and they remain in the file only for compatibility. On plain Spigot they do work, but they tell the server to abandon ticking mechanisms and entities halfway through, so TPS looks better purely because the server stops doing the work. Either way, leave them alone.

bukkit.yml: spawn limits, or how many mobs may live at once

bukkit.yml is rarely touched, but when several hundred mobs are alive per player, lowering spawn-limits does more than any other change. The limits are counted per player, so on a server with thirty people they multiply very quickly.

bukkit.yml
spawn-limits:
  monsters: 50
  animals: 8
  water-animals: 3
  water-ambient: 10
  ambient: 1
ticks-per:
  monster-spawns: 2
  animal-spawns: 400
  water-spawns: 400
  ambient-spawns: 400
  autosave: 6000
chunk-gc:
  period-in-ticks: 400
  • monsters: 50 instead of the default 70 means fewer monsters to tick and fewer collisions. On a survival server players will not notice, because away from caves the limit is rarely reached anyway.
  • ambient: 1 is bats. They contribute nothing beyond sound and work for the server.
  • monster-spawns: 2 attempts a spawn every other tick instead of every tick. That is half the work of the spawner for an almost unchanged mob count, because the population limit is the bottleneck anyway.
  • autosave: 6000 moves the world save to once every five minutes. Saving less often means stuttering less often, but also more to lose in a crash, so it only makes sense alongside backups that actually work.

paper-world-defaults.yml: where most of the real gain lives

This file contains optimisations Spigot does not have at all, which is why moving from Spigot to Paper is on its own the biggest optimisation available to you. Below are the settings that give a measurable effect without breaking mechanics.

config/paper-world-defaults.yml
chunks:
  max-auto-save-chunks-per-tick: 8
  delay-chunk-unloads-by: 10s
  prevent-moving-into-unloaded-chunks: true
collisions:
  max-entity-collisions: 2
entities:
  armor-stands:
    tick: false
  behavior:
    disable-chest-cat-detection: true
    experience-merge-max-value: 16
  spawning:
    despawn-ranges:
      monster:
        soft:
          horizontal: 28
          vertical: 28
        hard:
          horizontal: 96
          vertical: 96
    per-player-mob-spawns: true
    alt-item-despawn-rate:
      enabled: true
environment:
  optimize-explosions: true
  treasure-maps:
    find-already-discovered:
      loot-tables: true
hopper:
  disable-move-event: true
  ignore-occluding-blocks: true
misc:
  redstone-implementation: ALTERNATE_CURRENT
tick-rates:
  mob-spawner: 2
  sensor:
    villager:
      secondarypoisensor: 80
  behavior:
    villager:
      validatenearbypoi: 120

despawn-ranges has four levels, not two

Older guides show soft: 32 and hard: 128 as plain numbers. Paper now expects separate horizontal and vertical keys under soft and hard, and the default for each of them is the word default rather than a number. A bare number placed there is ignored.
SettingWhat it doesWhat to watch for
max-entity-collisions: 2Limits how many collisions an entity calculates per tick. With packed mob herds or a farm this is an order-of-magnitude difference.Mobs clip into each other, and farms that push mobs by crowding them may stop working.
hopper.disable-move-eventStops firing an event for every item a hopper moves. On a server with a sorting system this saves an enormous amount.Plugins watching item flow (chest protection, logging, custom crafting) will no longer see those events. Check before enabling.
despawn-rangesMobs beyond 96 blocks from the player disappear immediately, those closer than 28 never do.Farms relying on mobs accumulating far from the player will lose throughput.
optimize-explosionsA cheaper algorithm for calculating blast damage.Minimal differences in damage at the edge of a blast. Worth testing on a PvP server with creepers.
armor-stands.tick: falseArmour stands stop being ticked. Servers with decorations and holograms have thousands of them.Stands stop reacting to gravity and water. If you use them as part of a mechanic, leave ticking on.
alt-item-despawn-rateLets you set a shorter despawn time for junk like cobblestone and dirt without touching valuable items.Requires filling in the item list in the file. Enabling it without a list changes nothing.
tick-rates (villagers)Villagers recalculate their points of interest less often. In a large village this is one of the heaviest parts of the tick.Villagers are slower to find beds and workstations after the village changes.
Roughly ordered from the biggest to the smallest gain on a typical plugin server.

Redstone: one change sometimes worth more than the rest of the file

The misc.redstone-implementation key sits in paper-world-defaults.yml rather than in the global file, and getting that wrong is a mistake half the guides out there repeat. The default is VANILLA, with EIGENCRAFT and ALTERNATE_CURRENT as the alternatives. The latter is a from-scratch rewrite that only updates what actually changed, so in dust-heavy builds it can be many times faster than the vanilla algorithm.

When not to enable ALTERNATE_CURRENT

The algorithm does not reproduce every quirk of vanilla redstone, including the order in which neighbouring blocks are updated. Technical servers where players build circuits relying on those quirks should stay on VANILLA. If someone reports a broken contraption after the change, this is the first place to look.

paper-global.yml: a few small things to finish

The global file has little to offer in performance terms, because most of the switches live in the world configuration. These three are still worth knowing.

config/paper-global.yml
misc:
  region-file-cache-size: 256
player-auto-save:
  rate: -1
  max-per-tick: -1
chunk-system:
  io-threads: -1

A value of -1 under player-auto-save means the server takes its frequency from ticks-per.autosave in bukkit.yml and picks a sensible per-tick limit on its own, so if you set 6000 there, nothing else needs touching. io-threads below zero means a single thread for disk operations, which is perfectly sufficient for a small or medium server.

JVM flags: not server config, but it counts just as much

The best-tested set of flags for Minecraft servers is the so-called Aikar flags, a G1 garbage collector configuration that trades rare long pauses for frequent short ones. You will not see the effect in the average TPS, only in the disappearance of regular one-second freezes.

Aikar flags for 4 to 12 GB of memory
java -Xms8G -Xmx8G \
  -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 paper.jar nogui
  • Setting -Xms equal to -Xmx is a deliberate decision rather than a way to save memory. A heap that does not grow never forces an expensive resize mid-game.
  • Above 12 GB the set changes: G1NewSizePercent=40, G1MaxNewSizePercent=50, G1HeapRegionSize=16M, G1ReservePercent=15 and InitiatingHeapOccupancyPercent=20.
  • Do not hand the server all available memory. The JVM needs room outside the heap for metaspace, threads and network buffers, so leave roughly 1 to 2 GB of headroom. Otherwise the process gets killed by the system before you ever see a Java error.
  • Do not stitch flags together from several guides. The sets can contradict each other, and -XX:+UseZGC next to -XX:+UseG1GC is the fastest way to stop the server from starting at all.

On a managed panel you usually do not need this

On hosting with a ready-made panel the startup flags are already matched to the memory you were given, and the -Xmx value usually cannot even be pushed above your package. This section matters mainly on your own VPS, or when the panel lets you supply your own startup line.

Ready-made sets for three kinds of server

Different servers have different bottlenecks, so a single universal set does not exist. Below are starting points worth beginning from and then tuning with measurements.

SettingSurvival with friends (up to 10)Public with plugins (20 to 60)Modpack (up to 15)
view-distance866
simulation-distance644
spawn-limits: monsters704030
max-entity-collisions422
mob-spawn-range644
nerf-spawner-mobsfalsetruetrue
hopper.disable-move-eventtruedepends on your pluginsfalse, because mods often need it
redstone-implementationALTERNATE_CURRENTALTERNATE_CURRENTVANILLA
A starting point, not a verdict. After every change, check /mspt at peak hours.

Modpacks are a different league

On a modded server most of the load comes from the mods themselves rather than vanilla mechanics, and Forge and NeoForge have no Paper files at all. There, optimisation is mostly about shorter distances, adding performance mods and working out which mod generates the lag. The files described above apply to Paper and its forks, not to Forge.

Five things that look like optimisation but are not

  • Adding RAM to a server that has no RAM problem. Lag with the Can't keep up message is a processor problem on a single thread. More memory will not speed up tick calculation, and too large a heap makes garbage collector pauses longer.
  • Copying a config from someone else wholesale. Files from guides refer to older versions and contain keys your build no longer knows. Paper ignores unknown keys silently, so you will be convinced you configured something.
  • Disabling the watchdog. It masks the problem instead of solving it and takes away the one log you could have learned something from.
  • Turning off everything that can be turned off. A server with mob AI disabled, zero despawn and a clipped entity tick has excellent TPS and is no fun to play on. Optimisation is the search for the best ratio of gain to mechanics taken away from players.
  • Keeping ten plugins that do the same thing. Every plugin listens for events. Three land-protection plugins mean triple the work on every block placed, and that is one of the most frequent events on a server.

Frequently asked questions

Does paper.yml still exist?

No. Since Minecraft 1.19 Paper uses config/paper-global.yml and config/paper-world-defaults.yml. The old paper.yml is migrated automatically on the first start of a newer build and is no longer read.

Which should I lower first, view-distance or simulation-distance?

simulation-distance first. It governs the actual calculation of mobs and mechanisms, so it gives a bigger CPU win, and players notice it less than a shortened view distance. Lower the view distance only as a second step.

Do these settings work on Purpur and Pufferfish?

Yes, because both are Paper forks and inherit its entire configuration. On top of that they have their own files, purpur.yml and pufferfish.yml respectively, with further options, including more aggressive mob AI optimisations.

How long before a change shows an effect?

TPS and MSPT react immediately after a restart, but a trustworthy measurement needs normal traffic, so ideally compare /mspt at the same peak hour before and after. Changes to chunks and mob despawn only show after tens of minutes, once the world has cycled through.

Will lowering view-distance reduce player ping?

It will not reduce ping itself, because that depends on the distance to the server and the quality of the connection. It will reduce the amount of data sent to the client, which helps players on weaker connections and removes stutter when moving into new terrain.

Can I edit these files while the server is running?

You can save them, but the server reads its configuration at startup, so changes only apply after a restart. On top of that the server rewrites some of these files on shutdown, so a live edit may simply be wiped. It is safer to stop the server, change the file and start it again.


Optimisation only pays off on a sensible processor

Packages on highly clocked AMD Ryzen processors, which is exactly where the single thread ticking your world benefits. You edit the configuration files straight from the panel or over SFTP, and take a backup with one click before every change.

See Minecraft packages