9 min read

How to Reduce Entity and Mob Lag on a Minecraft Server

Diagnose and fix entity lag on a Paper server — measure with spark, then tune mob caps, activation range, despawn, and merge-radius in the right order.

How to Reduce Entity and Mob Lag on a Minecraft Server

Entity lag comes from too many things ticking at once — mobs from a farm, plus the dropped items and XP orbs piling up under it — and the fix is to count them before you change anything, then trim the worst offenders in spigot.yml, bukkit.yml, and paper-world-defaults.yml. A huge mob farm hogging the global cap, a chunk knee-deep in undespawned items, or an activation range so wide the server runs AI on mobs nobody's near: any of these can drag tick time up even when your RAM and CPU look fine. The trap is editing config blind. You can halve your spawn limits and still stutter if the real cost was a single farm chunk, so measure first. This is owner-side work on Paper/Spigot/Purpur — a player can't apply any of it to a server they don't own — and it pairs closely with the broader walkthrough on TPS lag spikes.

Measure first: is it actually entities?

Run /tps. A healthy server sits at 20 TPS, but TPS alone hides spikes, so the number that matters more is MSPT — milliseconds per tick. The tick budget is 50 ms; anything comfortably under that is fine, and the 95th-percentile MSPT is the most honest figure because average TPS can read a flat 20 while brief spikes still make movement stutter. /spark tps and /spark health give you that percentile breakdown at a glance.

Then confirm the cause with the profiler. spark is the modern tool for this — the old /timings on system was removed from recent Paper builds, so lead with spark and treat timings as legacy if you see it referenced in older guides. Run /spark profiler start, let it sample the main thread for a minute or two under normal load, and /spark profiler stop uploads a shareable web report. Entity load shows up there as a large slice of tick time under entity ticking and mob spawning. If you're chasing spikes specifically rather than steady load, /spark profiler start --only-ticks-over 100 profiles only the ticks that ran over 100 ms, which isolates the farm or chunk causing the stutter instead of averaging it away.

The report also points you at the heavy world and chunk. That matters because the fix for one runaway farm chunk is different from the fix for a server that's simply ticking too many chunks everywhere.

Tame the mob cap and where mobs spawn

The vanilla-style mob cap lives in bukkit.yml under spawn-limits, with separate numbers for monsters, animals, water-animals, water-ambient, and ambient. Lowering these caps the total number of natural mobs the server will keep alive at once.

On Paper, the more important lever is entities.spawning.per-player-mob-spawns: true in paper-world-defaults.yml. With it on, the cap is spread across each player rather than pooled globally, so one AFK player parked at a mob farm can't starve spawns for everyone else — and that same farm can't inflate the global entity count the way it would under a single shared pool. Leave it on. If you want a world to fall back to the bukkit.yml numbers, set entities.spawning.spawn-limits.<category>: -1.

Don't stop at the cap, though. mob-spawn-range in spigot.yml (default 8) is how many chunks out from a player mobs are allowed to spawn. Pulling it in concentrates spawns nearer to players, so a smaller cap still feels populated instead of empty. Keep mob-spawn-range at or below your effective simulation distance — spawning mobs in chunks that aren't simulated is wasted work.

Cut the cost of the mobs you keep

A mob you've spawned costs CPU every tick it runs its AI. entity-activation-range in spigot.yml is the distance in blocks within which an entity runs full AI; past that range it ticks at a reduced rate. The defaults look like this:

entity-activation-range:
  animals: 32
  monsters: 32
  raiders: 64
  misc: 16
  water: 16
  villagers: 32
  flying-monsters: 32

Trimming monsters and animals (say 32 down to 24) is a cheap win on a busy server, since most far-away mobs don't need full AI to be where you left them. The related wake-up-inactive block controls how often inactive mobs get a turn to act — monsters-every, monsters-for, monsters-max-per-tick, and the slower animals-every / villagers-every — and tick-inactive-villagers: true keeps villager workstations functioning. For spawner-heavy grinder servers, nerf-spawner-mobs: true disables most AI on mobs that came from a spawner, which is close to free.

Tracking is a separate cost from AI. entity-tracking-range (players: 128, animals/monsters/misc: 96, other: 64) sets how far away the server bothers sending entity updates to clients. There's rarely a reason to track entities far past where players can see them.

Stop the pileups: items, XP orbs, and farm chunks

Dropped items and experience orbs are entities too, and they pile up fast at a farm collection point. merge-radius in spigot.yml combines nearby ground items and XP orbs into single stacks and orbs, so a heap of drops ticks as a handful of entities instead of dozens. One caveat: the default value differs by build. Classic Spigot used item: 2.5 and exp: 3.0, but the current PaperMC reference shows item: 0.5 and exp: -1 (a value of 0 or below disables exp merging). Check what your own server actually generated rather than trusting any single number, and keep merge-radius modest — somewhere around 6 to 8 at most, because a large radius lets items merge through walls and appear to teleport.

For litter that never gets collected, item-despawn-rate (Spigot default 6000 ticks, which is five minutes) controls how long dropped items survive. Lowering it clears the floor faster. Paper's despawn-ranges go after mobs the same way: lowering the hard horizontal and vertical distances forces distant mobs to despawn outright, cutting the total tracked count. And for a single chunk that's run away — say an XP grinder drowning in orbs, or a skeleton trap packing a chunk with arrows — entities.spawning.entity-per-chunk-save-limit caps how many of a given type are saved per chunk (experience_orb, snowball, arrow, and so on), so one farm can't fill a chunk with thousands of one entity. The same crowded collection points also benefit from the maxEntityCramming gamerule (default 24; /gamerule maxEntityCramming 24, or 0 to disable) and Paper's collisions.max-entity-collisions (default 8), which both cap the cost of mobs stacked on top of each other.

When you just need the floor clean now, /kill @e[type=item] clears dropped items immediately, and if you run ClearLagg, /lagg clear does the same with a warning.

Right-size simulation distance

This is often the single biggest entity-lag win, and it's the one people forget. simulation-distance in server.properties directly bounds how many chunks tick entities at all — every chunk inside that radius is running mobs, redstone, and item physics. Dropping it from a high value (some hosts ship 10 or 12) to 6 can cut entity load dramatically because you're simply ticking fewer chunks. view-distance can stay higher for render purposes; it's simulation-distance that costs you. Pre-generating terrain with Chunky also helps, since it removes the generation spikes that otherwise stack on top of entity work when players explore. If trimming chunks doesn't move the needle, the problem may be memory pressure instead, and the RAM usage guide covers that side along with the Aikar JVM flags that keep garbage collection from causing its own spikes.

One version note: keep plugin servers on stable 26.1 for now. Paper's 26.2 "Chaos Cubed" builds are still experimental and flagged unsupported, so a server you're tuning for steady tick time is better off on the stable line. These levers are Paper/Spigot/Purpur specifics — Fabric servers tune entities through mods like Lithium and Carpet instead.

FAQ

Should I just delete all the dropped items with /kill @e[type=item]?

It's a fine emergency reset, but it's a blunt one: /kill @e[type=item] destroys every dropped item in loaded chunks, including a player's gear that fell when they died seconds ago. Use it to clear a litter spike, then fix the cause with merge-radius and a lower item-despawn-rate so it doesn't refill. If you run ClearLagg's /lagg clear, prefer it — it broadcasts a countdown so players can grab anything important first.

My TPS reads 20 but the game still stutters. What am I missing?

Average TPS is a smoothed number that hides short spikes, so trust the 95th-percentile MSPT from /spark health or /spark tps instead — if the average reads a clean 20 but that percentile is brushing or passing 50 ms, some chunks are blowing the tick budget intermittently. The next question is what is blowing it. Run /spark profiler start --only-ticks-over 100 to capture only those spikes, then read where the heavy slice lands: entity ticking points you back to a farm chunk or a mob-cramming collection point, while spikes sitting in garbage collection mean it's a memory problem and no spawn limit will touch it.

What's the difference between mob-spawn-range and simulation-distance?

simulation-distance (in server.properties) decides which chunks tick at all — it's the outer boundary of everything active, entities included. mob-spawn-range (in spigot.yml) decides how far from a player new mobs are allowed to spawn within that simulated area. Simulation distance is the bigger hammer for total entity load; spawn range shapes where the mobs you do allow end up. Keep spawn range at or below simulation distance so you're not asking the server to spawn mobs in chunks it isn't simulating.

Does turning per-player-mob-spawns on lower my total mob count?

Not by itself — it redistributes the cap rather than shrinking it. With per-player-mob-spawns: true, each player gets their own slice of the spawn limit instead of everyone competing for one global pool, which stops a single AFK farm from eating the whole cap. The practical effect on a populated server is that spawns feel fairer and one farm can't dominate the global count, but if you want fewer mobs overall you still lower the spawn-limits numbers in bukkit.yml.