1 Measure first — don't guess

Optimization without measurement is just randomly changing settings. Before you touch anything, install spark (a free profiler plugin/mod) and run a baseline:

/spark health          # quick snapshot: TPS, MSPT, memory, CPU
/spark profiler start  # then play/load the server for 5-15 min
/spark profiler stop   # gives you a shareable report link

The number that matters is MSPT (milliseconds per tick), not TPS. The server gets 50 ms per tick to do its work (1000 ms ÷ 20 ticks). If your median MSPT is under 50, you're keeping 20 TPS with headroom. If it's over 50, you physically cannot — and TPS will drop. Paper and Spigot can display a flat 20 TPS while ticks run long, which is why MSPT is the honest metric.

Skip the manual reading. Paste your spark link into our free Spark Report Analyzer — it reads your MSPT, TPS, memory, GC and JVM flags and tells you, in plain English, what's costing you the most.

2 View distance vs. simulation distance — the biggest lever

These two are separate settings (since 1.18) and confusing them wastes the most performance of anything on this list.

  • view-distance — how far chunks are sent to players to render. Costs bandwidth and a little memory.
  • simulation-distance — how far the server actually ticks things: mob spawning, redstone, crop growth, entity AI. This is the expensive one.

The trick is to keep view distance reasonable so the world still looks far, but pull simulation distance down so the server isn't ticking a huge area:

Setting (server.properties)RecommendedWhy
view-distance8 (6 if low-RAM, up to 10–12 for build servers)What players see. Cheap-ish.
simulation-distance4–6 (4 for performance, 5 default-ish)What the server ticks. Halving this is a huge TPS win.
network-compression-threshold256 (512 on busier servers)Compresses larger packets; raise it if you have bandwidth.

Dropping simulation distance from 10 to 5 alone can halve the area being simulated. Farms still work as long as they sit within simulation range of a player.

3 Entities are usually the real culprit

On most survival/SMP servers, the heaviest thing in a spark report is entities — mobs, item drops, and dropped-gear piles. Three settings tame them.

Entity activation range (spigot.yml)

Entities outside this range get their AI throttled. Vanilla defaults are generous; tighten them:

world-settings:
  default:
    entity-activation-range:
      animals: 16        # was 32
      monsters: 24       # keep >= 24 so mobs near players still behave
      raiders: 48
      misc: 8            # was 16
      water: 8
      villagers: 16      # was 32

Spawn limits & spawn range

By default a single player can have ~70 monsters, 10 animals and 15 water creatures around them — far more than most servers need. Lower the per-player limits in bukkit.yml and shrink mob-spawn-range in spigot.yml (never above your simulation-distance):

spawn-limits:        # bukkit.yml (per-player on Paper)
  monsters: 60
  animals: 10
  water-animals: 5

mob-spawn-range: 4   # spigot.yml — fewer candidate chunks to spawn in

Merge radius

Merging nearby dropped items and exp orbs into single entities cuts entity count dramatically near farms. In spigot.yml: merge-radius: item: 3.0 and exp: 4.0 (higher = fewer entities).

4 Use Paper and turn on its optimizations

If you're on Spigot or Bukkit, the single best change you can make is switching to Paper — it's a drop-in replacement (same plugins, same worlds) with far more performance options. On Paper 1.19+, the big ones live in config/paper-world-defaults.yml:

Paper settingValueWhat it does
hopper.disable-move-eventtrueHuge win for hopper-heavy farms (skips a costly event). Rare plugin filters may need it off.
collisions.max-entity-collisions2Caps the collision checks crammed mobs do (default 8).
entities.spawning.per-player-mob-spawnstrueDistributes mob spawns fairly, fewer wasted spawns.
chunks.prevent-moving-into-unloaded-chunkstrueStops elytra/boat freezes from racing into ungenerated chunks.
chunks.delay-chunk-unloads-by10sStops constant load/unload thrash near spawn.
environment.optimize-explosionstruePaper's faster explosion math (TNT, creepers, beds).
misc.update-pathfinding-on-block-updatefalseAvoids recalculating mob paths on every block change.

Purpur (a fork of Paper) adds even more toggles in purpur.yml if you want to go further. Pufferfish is another performance-focused option for big modded-style setups.

Don't want to hand-edit four config files?

Answer six questions and our Optimization Wizard outputs tuned paper-world-defaults.yml, spigot.yml, bukkit.yml and server.properties — every value explained.

Open the Wizard

5 Memory, garbage collection & Aikar's flags

This is where most people get it backwards. More RAM does not mean more performance. Beyond what your server actually uses, extra heap just means longer garbage-collection pauses — which show up as periodic lag spikes (high 95th-percentile MSPT in spark, low median).

  • Right-size the heap. Most vanilla/plugin servers are happy with 4–8 GB; large modpacks 8–12 GB. Allocating 16 GB to a 6-GB server makes GC worse, not better.
  • Use Aikar's flags. This is a well-tuned set of G1GC start flags that smooth out garbage collection — often the single biggest TPS win after distances. Grab them from the Paper docs and put them in your start command.
  • Leave RAM for the OS. Never allocate 100% of the machine's memory to Java — the OS and off-heap need headroom.
Reading GC in spark: a low median MSPT but high spikes usually means GC pauses or a periodic task — not constant overload. Check the GC section: long or frequent pauses point to too-large heap, a memory leak, or missing flags.

6 Plugins: fewer, leaner, updated

Every plugin costs something each tick, even idle. Three rules:

  • Update everything. Old builds of popular plugins leak performance that newer versions fixed.
  • Don't double up. Two anti-cheats, two chat plugins, or two protection plugins fight each other and waste ticks.
  • Profile, don't guess. In spark's call tree, expand the biggest node under Server Thread until you hit a plugin name — that's your offender. Update it, configure it, or replace it.

7 When it's not config — it's the hardware

Minecraft's server runs its main game loop on a single thread. That means core count barely matters; single-thread clock speed does. A 32-core server CPU at 2.3 GHz will lag where a 4-core chip at 5 GHz sails through, because the main tick can only use one core at a time.

So if spark shows your config is already lean — low entity counts, reasonable plugins, healthy GC — and you still can't hold 20 TPS, you've hit your host's CPU ceiling. Cheap "unlimited" panels that cram hundreds of servers onto slow many-core CPUs are the usual cause.

Optimized everything and still capped?

Solace runs Minecraft on high-clock CPUs — the single-thread speed Minecraft lives on — with NVMe storage and DDoS protection. Paper preinstalled, live in 60 seconds.

View Minecraft hosting

8 Quick recap

  1. Baseline with /spark health or /spark profiler. Watch MSPT, not TPS.
  2. Set simulation-distance 4–6, view-distance ~8.
  3. Tighten entity activation range, spawn limits, and merge radius.
  4. Run Paper and enable its anti-lag options (hopper event, collisions, chunk settings).
  5. Right-size RAM and add Aikar's flags — don't over-allocate.
  6. Update and trim plugins; profile the call tree for the worst one.
  7. Re-run spark and compare. If config is clean and you still lag, it's the host's CPU.