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.
| Metric | Ideal | Acceptable | Problematic |
|---|---|---|---|
| TPS | 20.0 | 18-20 | <15 |
| MSPT (ms/tick) | <30ms | 30-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:
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 --noguiWhat the Flags Do
| Flag | Value | Description |
|---|---|---|
| <code>-Xms/-Xmx</code> | 8G | Min/max heap size (must be equal) |
| <code>-XX:+UseG1GC</code> | — | Use the G1 garbage collector |
| <code>-XX:MaxGCPauseMillis</code> | 200 | Target GC pause duration (ms) |
| <code>-XX:+AlwaysPreTouch</code> | — | Reserve all RAM at startup |
| <code>-XX:G1NewSizePercent</code> | 30 | Minimum young gen size (%) |
| <code>-XX:G1MaxNewSizePercent</code> | 40 | Maximum young gen size (%) |
| <code>-XX:G1HeapRegionSize</code> | 8M | Heap region size (use 16M for 12GB+) |
| <code>-XX:G1ReservePercent</code> | 20 | Heap reserved for emergencies (%) |
| <code>-XX:MaxTenuringThreshold</code> | 1 | Move objects to old gen after 1 GC |
| <code>-XX:SurvivorRatio</code> | 32 | Survivor space ratio |
RAM Recommendations
| Player Count | Recommended RAM | Note |
|---|---|---|
| 1-10 | 2-4 GB | Vanilla or few plugins |
| 10-30 | 4-6 GB | Moderate plugin load |
| 30-60 | 6-10 GB | Many plugins + worlds |
| 60-100 | 10-14 GB | Busy server |
| 100+ | 16+ GB | Dedicated server required |
server.properties
The server's core configuration file. The settings that matter for performance:
| Setting | Default | Recommended | Description |
|---|---|---|---|
| <code>view-distance</code> | 10 | 6-7 | Chunk distance sent to the player |
| <code>simulation-distance</code> | 10 | 4-5 | Chunk distance that is actively ticked |
| <code>network-compression-threshold</code> | 256 | 256 | Packet compression threshold (bytes) |
| <code>max-tick-time</code> | 60000 | 60000 | Watchdog timeout (ms) |
| <code>spawn-protection</code> | 16 | 16 | Spawn protection radius |
paper-global.yml
Chunk Loading
chunk-loading-basic:
autoconfig-send-distance: true
player-max-concurrent-chunk-generates: 0
player-max-concurrent-chunk-loads: 0Packet Limiter
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.0Collision
collisions:
enable-player-collisions: false # saves CPU
send-full-pos-for-entity-teleport: truepaper-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:
entity-activation-range:
animals: 16
monsters: 24
raiders: 48
misc: 8
water: 8
villagers: 32
flying-monsters: 32Despawn Settings
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: 48Spawn Limits
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: 1Merge Radius
merge-radius:
item: 3.5 # merge items on the ground
exp: 4.0 # merge XP orbsHopper Optimization
hopper:
cooldown-when-full: true
disable-move-event: false
ignore-occluding-blocks: falseRedstone
# The Alternate Current redstone implementation is much faster than vanilla
redstone-implementation: ALTERNATE_CURRENTOther Important Settings
| Setting | Recommended | Description |
|---|---|---|
| <code>per-player-mob-spawns</code> | true | Per-player mob spawning (fairer) |
| <code>max-entity-collisions</code> | 4 | Maximum entity collisions |
| <code>disable-treasure-maps</code> | true | Disable treasure map searches (they cause lag) |
| <code>update-pathfinding-on-block-update</code> | false | Recalculate pathfinding on block changes |
| <code>fix-climbing-bypassing-cramming-rule</code> | true | Climbing exploit fix |
| <code>armor-stands.tick</code> | false | Disable armor stand ticking |
spigot.yml
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: falsebukkit.yml
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: 6000Pre-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
/chunky radius 5000
/chunky start
/chunky pause # to stop
/chunky continue # to resumeA 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
/worldborder set 10000 # 10,000 block diameter
/worldborder center 0 0 # centre pointPerformance 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
| Command | Description |
|---|---|
| <code>/spark profiler start</code> | Start CPU profiling |
| <code>/spark profiler stop</code> | Stop profiling and generate the report |
| <code>/spark tps</code> | Show the current TPS |
| <code>/spark tickmonitor</code> | Start per-tick monitoring |
| <code>/spark health</code> | Server health summary (CPU, RAM, TPS) |
| <code>/spark gc</code> | Garbage 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
| Plugin | Function | Note |
|---|---|---|
| <strong>Spark</strong> | TPS/RAM monitoring, profiler | Essential — every server should have it |
| <strong>Chunky</strong> | World pre-generation | Run it after installation |
| <strong>ViewDistanceTweaks</strong> | Dynamic view distance | Adjusts automatically to player count |
| <strong>ClearLagg</strong> | Item/entity cleanup | Must be configured; do not use it aggressively |
| <strong>FarmControl</strong> | Farm limits | Prevents mob farm abuse |
| <strong>VillagerOptimiser</strong> | Optimises villager AI | Fixes villager lag |
| <strong>EntityTrackerFixer</strong> | Entity tracking fixes | Effective 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-5set - ☐
view-distance: 6-7set - ☐ Spawn limits lowered (monsters: 30, animals: 8)
- ☐
per-player-mob-spawns: trueenabled - ☐ 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