TPS and the Tick Loop

A Minecraft server processes exactly 20 ticks per second. Every tick has to finish within 50 milliseconds. If tick time exceeds 50ms the server slows down - that is what we call lag.

MetricIdealAcceptableProblematic
TPS20.018-20<15
MSPT (ms/tick)<30ms30-50ms>50ms
Spark sleep %>80%20-80%<5%

What gets processed in the tick loop, in order: player movement, entity AI, redstone, block ticks, chunk loading, network packets. A bottleneck in any one of them means a TPS drop.

JVM Flags (Startup Parameters)

JVM flags determine how the server uses the Java virtual machine. The right flags minimise GC (Garbage Collection) pauses.

Aikar's Flags (the Standard)

The gold standard for Minecraft servers. Recommended for most setups:

bash
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

What the Flags Do

FlagValueDescription
-Xms/-Xmx8GMin/max heap size (must be equal)
-XX:+UseG1GC-Use the G1 garbage collector
-XX:MaxGCPauseMillis200Target GC pause duration (ms)
-XX:+AlwaysPreTouch-Reserve all RAM at startup
-XX:G1NewSizePercent30Minimum young gen size (%)
-XX:G1MaxNewSizePercent40Maximum young gen size (%)
-XX:G1HeapRegionSize8MHeap region size (use 16M for 12GB+)
-XX:G1ReservePercent20Heap reserved for emergencies (%)
-XX:MaxTenuringThreshold1Move objects to old gen after 1 GC
-XX:SurvivorRatio32Survivor space ratio

RAM Recommendations

Player CountRecommended RAMNote
1-102-4 GBVanilla or few plugins
10-304-6 GBModerate plugin load
30-606-10 GBMany plugins + worlds
60-10010-14 GBBusy server
100+16+ GBDedicated server required

server.properties

The server's core configuration file. The settings that matter for performance:

SettingDefaultRecommendedDescription
view-distance106-7Chunk distance sent to the player
simulation-distance104-5Chunk distance that is actively ticked
network-compression-threshold256256Packet compression threshold (bytes)
max-tick-time6000060000Watchdog timeout (ms)
spawn-protection1616Spawn protection radius

paper-global.yml

Chunk Loading

yaml
chunk-loading-basic:
  autoconfig-send-distance: true
  player-max-concurrent-chunk-generates: 0
  player-max-concurrent-chunk-loads: 0

Packet Limiter

yaml
packet-limiter:
  all-packets:
    action: KICK
    interval: 7.0
    max-packet-rate: 500.0
  overrides:
    ServerboundPlaceRecipePacket:
      action: DROP
      interval: 4.0
      max-packet-rate: 5.0

Collision

yaml
collisions:
  enable-player-collisions: false  # saves CPU
  send-full-pos-for-entity-teleport: true

paper-world.yml (World Settings)

The settings with the biggest performance impact live here. They can be configured per world.

Entity Activation Range

The distance within which entity AI is processed. Lower = less CPU usage:

yaml
entity-activation-range:
  animals: 16
  monsters: 24
  raiders: 48
  misc: 8
  water: 8
  villagers: 32
  flying-monsters: 32

Despawn Settings

yaml
despawn-ranges:
  monster:
    soft: 30    # random despawn chance at this distance
    hard: 56    # instant despawn at this distance
  creature:
    soft: 30
    hard: 56
  misc:
    soft: 28
    hard: 48

Spawn Limits

yaml
spawn-limits:
  monsters: 30      # default 70 - cut it in half
  animals: 8
  water-animals: 3
  water-ambient: 3
  water-underground-creature: 3
  axolotls: 3
  ambient: 1

Merge Radius

yaml
merge-radius:
  item: 3.5       # merge items on the ground
  exp: 4.0        # merge XP orbs

Hopper Optimization

yaml
hopper:
  cooldown-when-full: true
  disable-move-event: false
  ignore-occluding-blocks: false

Redstone

yaml
# The Alternate Current redstone implementation is much faster than vanilla
redstone-implementation: ALTERNATE_CURRENT

Other Important Settings

SettingRecommendedDescription
per-player-mob-spawnstruePer-player mob spawning (fairer)
max-entity-collisions4Maximum entity collisions
disable-treasure-mapstrueDisable treasure map searches (they cause lag)
update-pathfinding-on-block-updatefalseRecalculate pathfinding on block changes
fix-climbing-bypassing-cramming-ruletrueClimbing exploit fix
armor-stands.tickfalseDisable armor stand ticking

spigot.yml

yaml
world-settings:
  default:
    entity-activation-range:
      animals: 16
      monsters: 24
      raiders: 48
      misc: 8
      water: 8
      tick-inactive-villagers: true
    merge-radius:
      item: 4.0
      exp: 6.0
    mob-spawn-range: 4
    item-despawn-rate: 6000
    arrow-despawn-rate: 300
    nerf-spawner-mobs: false

bukkit.yml

yaml
spawn-limits:
  monsters: 30
  animals: 8
  water-animals: 3
  water-ambient: 3
  water-underground-creature: 3
  axolotls: 3
  ambient: 1

chunk-gc:
  period-in-ticks: 400

ticks-per:
  animal-spawns: 400
  monster-spawns: 4
  water-spawns: 1
  water-ambient-spawns: 1
  water-underground-creature-spawns: 1
  axolotl-spawns: 1
  ambient-spawns: 1
  autosave: 6000

Pre-Generation (Generating the World in Advance)

Chunk generation is the single most CPU-intensive operation. Generating the world in advance removes that load at runtime.

The Chunky Plugin

text
/chunky radius 5000
/chunky start
/chunky pause       # to stop
/chunky continue    # to resume

A 5000 block radius = an area of roughly 10,000x10,000. This can take a long time (30 minutes to several hours). Run it while the server is empty.

World Border

text
/worldborder set 10000    # 10,000 block diameter
/worldborder center 0 0   # centre point

Performance Analysis with Spark

Spark is the most advanced profiling tool for Minecraft servers. It is used to find the cause of a TPS drop.

Installation and Basic Commands

CommandDescription
/spark profiler startStart CPU profiling
/spark profiler stopStop profiling and generate the report
/spark tpsShow the current TPS
/spark tickmonitorStart per-tick monitoring
/spark healthServer health summary (CPU, RAM, TPS)
/spark gcGarbage collection statistics

Reading the Report

  • waitForNextTick() sleep > 80%: the server is healthy and has spare capacity
  • Sleep 20-80%: under normal load, keep monitoring
  • Sleep < 5%: critical - lag spikes are inevitable
  • The thread eating the most CPU: that is your bottleneck - it could be entities, redstone or chunk generation

Performance Plugins

PluginFunctionNote
SparkTPS/RAM monitoring, profilerEssential - every server should have it
ChunkyWorld pre-generationRun it after installation
ViewDistanceTweaksDynamic view distanceAdjusts automatically to player count
ClearLaggItem/entity cleanupMust be configured; do not use it aggressively
FarmControlFarm limitsPrevents mob farm abuse
VillagerOptimiserOptimises villager AIFixes villager lag
EntityTrackerFixerEntity tracking fixesEffective on large servers

Common Mistakes

  • Xms ≠ Xmx: the two must be equal, otherwise you get stutter at runtime
  • Too much RAM: allocating 16GB+ lengthens GC pauses. Do not give the server more RAM than it needs
  • view-distance too high: every extra chunk costs CPU exponentially. 6-7 is enough
  • Using /reload: it causes memory leaks and plugin errors. Always restart instead
  • No world border: players can generate infinite chunks and blow up your disk and CPU
  • Spark instead of Timings: Timings is deprecated, Spark is far more detailed and accurate
  • Hopper farms: hundreds of hoppers = serious lag. Use the water stream alternative

Optimization Checklist

  • ☐ JVM flags (Aikar) configured
  • ☐ simulation-distance: 4-5 set
  • ☐ view-distance: 6-7 set
  • ☐ Spawn limits lowered (monsters: 30, animals: 8)
  • ☐ per-player-mob-spawns: true enabled
  • ☐ Entity activation range lowered
  • ☐ redstone-implementation: ALTERNATE_CURRENT
  • ☐ World pre-generated (Chunky)
  • ☐ World border set
  • ☐ Spark profiler installed
  • ☐ disable-treasure-maps: true
  • ☐ Hopper cooldown configured
  • ☐ Player collision disabled