Optimizing Paper Server TPS: The Complete 2026 Playbook
A practical, step-by-step guide to diagnosing and fixing TPS issues on a Paper Minecraft server - from spark profiling to paper.yml tuning to JVM flags.
Fabricio Souza
Founder, GeneX Plugins · 7+ years building Minecraft plugins
TPS dropped below 20. Players are complaining about rubberbanding. Your control panel's CPU graph is pegged. You've probably already googled "minecraft server lag fix" and waded through three pages of forum posts from 2017 telling you to change view-distance and pray.
This is the actual playbook. Diagnostic-first, evidence-based, in the order I'd run if I parachuted into your server right now.
TPS, MSPT, and what "lag" actually means
Before fixing anything, get the vocabulary right.
- TPS (ticks per second) - target is 20. Anything below 20 means the server can't simulate the world fast enough. 19.5 is unnoticeable; 15 is rubberbanding; 10 is unplayable.
- MSPT (milliseconds per tick) - the actual time each tick takes. 50ms is the breakpoint - below 50ms means TPS stays at 20; above 50ms means TPS drops.
- "Lag" is a player word for at least three different problems: low TPS (server can't tick fast enough), high ping (network latency to the server), and packet loss (network unreliability). They have different causes and different fixes.
What we're fixing in this post is TPS/MSPT. If players have high ping but your server reports TPS 20.0, that's a network problem - host them somewhere closer or use a proxy.
Step 1: Install spark before changing anything
You cannot fix what you can't measure. Install spark right now and run a profile.
# in-game or from console:
/spark profiler start
# play normally for 5-10 minutes
/spark profiler stopSpark produces a flamegraph showing exactly which code is eating your tick time. The top entries are your real problems. Everything else in this post is for after you've looked at a spark report.
Step 2: Read the spark report
The most common findings, in rough order of frequency:
| Top entry | Most likely cause |
|---|---|
World.tick / LevelChunk.tick | Too many ticking entities or chunks loaded |
| Specific plugin name | That plugin has a bad loop or expensive operation |
EntityTracker | Too many entities being tracked, or render distance too high |
Chunk.save / I/O | Disk is slow, or chunk saves too frequent |
MerchantOffer.tryToSetSpecialPrice / villagers | Villager-heavy area causing trade refresh storms |
Sensors (mob AI) | Mob AI eating CPU, common with mob farms |
Match your top entry to the right section below.
Step 3: Common fixes by category
Too many entities (item drops, mobs, projectiles)
If entityTick or LevelEntityGetter is in your top 3, you have too many entities active. Common culprits: mob farms, dropped items in spawn, large arrow swarms from skeletons.
Fixes in paper.yml / paper-world-defaults.yml (location depends on Paper version):
entities:
spawning:
despawn-ranges:
monster:
hard: 96 # was 128 default - more aggressive despawn
soft: 32
animal:
hard: 96
soft: 32
behavior:
# Tick villagers less aggressively when far from players
villager:
behavior-tick-rate: 2For dropped items specifically, set a global merge radius and stricter despawn:
entities:
spawning:
alt-item-despawn-rate:
enabled: true
delay:
default: 6000 # 5 minutes instead of vanilla 5Mob farms eating your TPS
Mob farms are explicitly designed to maximize entity count in a chunk. The fix isn't to ban them; it's to cap them.
entities:
spawning:
per-player-mob-spawns: true # respects mob caps per player
spawn-limits:
monster: 35 # default 70 - tighten
animal: 8
ambient: 1
water-animal: 3Beyond config, point players at the WildStacker or RoseStacker pattern - stacked mobs are dramatically cheaper to tick than individual ones.
Chunk load thrash (constant load/unload)
Spark entry: ChunkHolder or ServerChunkCache heavy.
Cause: Players moving fast (Elytra, horses) across unloaded chunks. The server constantly generates, ticks, and unloads chunks just behind them.
Fixes:
- Reduce
view-distanceinserver.propertiesfrom 10 to 8. Even 6 is fine on a busy server. Players will rarely notice unless they're in flat terrain. - Reduce
simulation-distanceto 4 or 5. This is the radius around players where mobs, redstone, and crops actually tick. Most players don't notice the difference between 4 and 10. - Pre-generate the world with Chunky. Pre-generated chunks load faster from disk than generating on-the-fly.
Villagers are nuking everything
If a village or trading hall shows up in spark, your trades-per-tick is the killer.
entities:
behavior:
villager:
behavior-tick-rate: 3 # only run AI every 3 ticks when far from players
behavior-tick-rate-distance: 25For trading hall builds (50+ villagers in one room), the only real fix is to redesign the build with stacked floors and gates that disable trades when no player is present. Config alone won't save a 200-villager megafactory.
A specific plugin is the problem
Spark named a specific plugin. Now you have to figure out why.
- Look at the plugin's flame for a sub-method - is it a particular feature?
- Check the plugin's config for the offending feature - it likely has a frequency knob.
- If no knob: open an issue with the plugin author with the spark report attached. Most maintainers respond within a few days.
Worst case: replace the plugin. There's almost always an alternative; even highly customized plugins have substitutes within a category. We've done plugin-swap audits as part of custom dev engagements - sometimes the cheapest fix is replacing two badly-written plugins with one well-written one.
Disk I/O is slow
Spark entry: Chunk.save, Region.write, anything with IOException showing up.
Cause: you're on a hosted server with slow disks (HDD instead of SSD, or contention with other VMs). The fix is hardware unless you can:
- Reduce save frequency:
paper.yml→chunks.auto-save-interval: 6000(5 min instead of 1 min default - some loss-of-data risk on crash) - Move to better hosting. Modern Minecraft on slow HDD storage is genuinely painful. NVMe is mandatory for any server above 50 concurrent.
Step 4: JVM flags (the Aikar's flags story)
You'll see Aikar's flags recommended everywhere. As of 2026 they're still the right baseline, though some defaults have improved. Use them:
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 noguiThe key bits:
-Xmsand-Xmxequal. Don't let the heap grow at runtime - reserve it all upfront. Set both to roughly 70% of available RAM, leaving headroom for the OS and other processes.- G1GC, not Shenandoah or ZGC. Despite their theoretical benefits, neither has played well with Minecraft's allocation patterns in production testing.
-XX:+AlwaysPreTouchallocates the full heap on startup. Slightly slower boot, dramatically smoother runtime.
Step 5: Network and host
If TPS is fine but players still report lag:
- Ping check: have players run
ping yourserver.com. Anything under 100ms is fine, 100-200ms is noticeable on PvP, 200ms+ is bad. - Bandwidth check: a busy server pushes ~50KB/s per player. 50 players = 2.5MB/s upload. Most home connections can't sustain this; many hosts cap bandwidth before they cap CPU.
- Packet loss:
mtr yourserver.comfrom a player. Any loss above 0% on the destination row indicates network problems between player and server. Usually a hosting issue.
Step 6: When you've done everything and it's still slow
If you've installed spark, tuned paper.yml, applied JVM flags, swapped problem plugins, and you're still at 18 TPS - the cause is one of:
- Genuinely too many concurrent players for one core. This is where Folia becomes worth evaluating. But check the entire flow chart on that post first - Folia isn't a free win.
- A custom plugin you wrote with a hot loop. Profile it, find the loop, async it.
- An exotic redstone contraption. Spark will show this clearly. Talk to the builder about restructuring.
- CPU starvation from neighboring VMs. Bad shared hosting. The fix is moving providers.
What you should run weekly
Optimization isn't a one-time job. A weekly checklist that takes 5 minutes:
- Run
spark profiler start, leave for 10 min during peak,stop, screenshot top 5. - Compare to last week's top 5. New entry climbing? Investigate.
- Check
ms[t]from spark health - any large GC pauses? Heap might be too small or fragmented. - Check
top/htopfor processes consuming CPU outside Java. Some hosts run mining malware that landed on the box.
This 5-minute weekly check catches 80% of slow-creep problems before players notice.
Common myths to ignore
- "Lower view-distance to 3" - this hurts gameplay more than it helps TPS at modern view distances. View-distance 8 is fine on most servers.
- "Use ParallelGC instead of G1GC, it's faster!" - it's faster on synthetic benchmarks and worse on Minecraft. Trust the consensus.
- "You need 32GB of RAM for 50 players" - false. 8GB allocated to the JVM is enough for 50-100 players on a well-optimized server. More RAM doesn't help past the point where GC pressure is gone.
- "Disable autosave entirely" - on the day your server crashes, you'll lose hours of player data. Don't do this.
Bottom line
Diagnose with spark, fix the top 1-3 entries, repeat. The configs in this post are starting points - your spark report tells you which ones actually matter for your server.
If you've worked through this and your TPS is still bad - or you'd rather have someone else dig through your spark reports - we do server optimization audits as part of our custom plugin work. Usually we find 30-50% wins from config and plugin swaps alone, without writing any new code.
Got a spark report you can't decipher? Drop it in our Discord and we'll point you at the right config knob.
Last updated . Spotted a mistake? Let us know.