⚑ How to Reduce Minecraft Server Lag β€” Complete 2026 Guide

πŸ“… March 3, 2026 ⏱️ 18 min read 🏷️ Paper 1.21 Β· Optimization Β· Intermediate ✍️ OliveerF Network

Server lag in Minecraft almost always has a root cause β€” it's rarely "just bad hardware." This guide walks through the complete process of diagnosing and fixing lag on a Paper 1.21 server, from measuring TPS with Spark to fine-tuning Paper's config files. Every recommendation here has been tested on servers with 20-60 concurrent players.

πŸ“‹ Contents

  1. What is TPS and how to measure it
  2. Aikar JVM Flags β€” the single biggest win
  3. Paper configuration tuning
  4. Using Spark to find the actual lag source
  5. Chunk pre-generation with Chunky
  6. Entity and mob management
  7. Plugin audit and common offenders
  8. Quick checklist

πŸ“Š What is TPS and How to Measure It

TPS stands for Ticks Per Second. Minecraft runs at 20 TPS β€” every game tick advances time, moves entities, processes redstone, runs mob AI, and so on. When the server can't keep up with the workload, TPS drops below 20 and the game feels laggy.

20 TPSβœ… Perfect β€” everything runs smoothly
18–19 TPSβœ… Acceptable β€” minor lag, barely noticeable
15–17 TPS⚠️ Noticeable lag β€” players will feel rubberbanding
10–14 TPS⚠️ Serious lag β€” combat is broken, mobs freeze
<10 TPS❌ Critical β€” server is essentially unplayable

The fastest way to check TPS is with the Spark plugin. Run /spark tps in-game or in console to see current TPS averaged over 5 seconds, 1 minute, and 5 minutes. The 5-minute average is the most useful β€” a brief TPS dip from a large explosion doesn't mean you have a chronic lag problem.

You can also check with Paper's built-in /tps command, but Spark gives much more detail including CPU usage, memory breakdown, and tick duration graphs.

Client lag vs server lag: If players report "lag" but your TPS is 20, the issue is likely client-side frame drops, high chunk render distance, or player internet latency β€” not server performance. Don't spend time optimizing a 20 TPS server.

πŸš€ Aikar JVM Flags β€” The Single Biggest Win

The JVM's garbage collector (GC) is responsible for cleaning up unused memory. By default, Java uses a GC configuration suited for desktop applications, not for a game server that allocates thousands of objects per second. Aikar's flags tune the G1 Garbage Collector specifically for Minecraft's memory patterns.

Create a start.sh (Linux/Mac) or start.bat (Windows) with these flags:

# start.sh β€” Linux/macOS
#!/bin/bash
java \
  -Xms4G -Xmx4G \
  -XX:+UseG1GC \
  -XX:+ParallelRefProcEnabled \
  -XX:MaxGCPauseMillis=200 \
  -XX:+UnlockExperimentalVMOptions \
  -XX:+DisableExplicitGC \
  -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 \
  -Dusing.aikars.flags=https://mcflags.emc.gs \
  -Daikars.new.flags=true \
  -jar paper.jar --nogui
:: start.bat β€” Windows
java -Xms4G -Xmx4G -XX:+UseG1GC -XX:+ParallelRefProcEnabled ^
-XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions ^
-XX:+DisableExplicitGC -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 ^
-Dusing.aikars.flags=https://mcflags.emc.gs ^
-Daikars.new.flags=true -jar paper.jar --nogui
pause
How much RAM to allocate? Set -Xms and -Xmx to the same value. This prevents JVM from requesting more memory at runtime (which causes brief pauses). Rule of thumb:

βš™οΈ Paper Configuration Tuning

Paper exposes hundreds of configuration options not available in vanilla Minecraft. The file you'll edit most is config/paper-world-defaults.yml (Paper 1.19+). Here are the most impactful settings:

# config/paper-world-defaults.yml

entities:
  spawning:
    # Lower mob spawn attempts per chunk per tick
    spawn-limits:
      monsters: 50       # Default: 70 β€” reduce on busy servers
      animals: 8         # Default: 10
      water-animals: 3
      ambient: 5

environment:
  # How many chunks ahead of players are SIMULATED (mob AI, redstone, etc)
  # This is different from view-distance (rendering only)
  simulation-distance: 6  # Default: 10 β€” HUGE performance impact

chunks:
  # How many chunks players can SEE (less simulation overhead)
  view-distance: 8        # Default: 10

# In paper.yml (older config location)
entity-per-chunk-save-limit:
  experience_orb: 50   # Limit XP orbs per chunk (huge lag source)
  arrow: 100
  snowball: 20

tick-rates:
  grass-spread: 4      # Default: 1 β€” grass spread ticks every 4 ticks instead of 1
  container-update: 1  # Don't change this

# Entity activation ranges (mobs outside range tick less frequently)
entity-activation-range:
  animals: 24          # Default: 32 β€” animals only activate fully within 24 blocks
  monsters: 32         # Default: 32
  raiders: 48
  misc: 12
  tick-inactive-villagers: false  # BIG win β€” villagers are expensive
⚠️ Don't blindly copy-paste configs. Lowering simulation-distance too much breaks farm mechanics (mob spawners, redstone clocks stop working for players far away). Test changes on a development server first.

πŸ” Using Spark to Find the Actual Lag Source

Guessing where lag comes from is inefficient. Spark gives you a CPU flamegraph that shows exactly which code is consuming the most time. Here's the workflow:

1

Start a profiling session

In console, run: spark profiler --timeout 120
This profiles 120 seconds of server activity. Run during peak hours when you have players online β€” profiling an empty server shows nothing useful.

2

Open the flame graph URL

Spark uploads the report to https://spark.lucko.me/ and prints the URL in console. Open it. You'll see a horizontal flame graph where the width of each block = time consumed.

3

Identify the hot paths

Look for wide blocks high in the call stack. Common culprits:
β€” EntityAI.tick() β†’ too many mobs with complex AI
β€” BlockListener (plugin name) β†’ a plugin doing work every block change
β€” WorldguardPlugin β†’ WorldGuard checking regions too often
β€” AsyncTabCompleter β†’ plugin with expensive tab completion

4

Check health summary

Run spark health in console. It shows memory usage, GC activity, disk I/O, and CPU load with traffic-light indicators. If GC is shown in red, the JVM flags or RAM allocation needs fixing.

πŸ—ΊοΈ Chunk Pre-Generation with Chunky

Every time a player explores a new area, the server must generate that chunk from scratch β€” computing terrain, structures, ores, and biomes. This is one of the most expensive operations Minecraft performs. If you don't pre-generate, every explorer triggers a TPS spike.

The solution is to pre-generate the world before players log in using the Chunky plugin:

# In server console β€” pre-generate a 5000-block radius (10000x10000 area)
/chunky start radius 5000

# For a 2500-block radius (more reasonable for small servers)
/chunky start radius 2500

# Check progress
/chunky status

This will take time β€” anywhere from 30 minutes to several hours depending on world seed and hardware. Run it before players join or during a maintenance window. The TPS improvement for new player exploration is immediate and dramatic.

Also set a world border to prevent infinite world growth:

# Set world border to 10000 x 10000 (5000 blocks each direction from 0,0)
/worldborder set 10000

πŸ„ Entity and Mob Management

Entities β€” mobs, animals, item frames, armor stands, dropped items β€” are one of the heaviest per-tick costs. Each entity with active AI ticks every game tick. Here's how to control entity lag:

Clear excessive mobs and dropped items

# Kill all dropped items in all worlds
/kill @e[type=item]

# Kill arrows (accumulate from skeleton farms)
/kill @e[type=arrow]

# Kill all mobs except players
/kill @e[type=!player]

Find lag-causing entities with Spark

/spark entities

This shows a breakdown of entity counts per chunk and per world. If you see "5000 zombies in chunk (32, -17)" β€” someone has a mob farm that's out of control.

Villager optimization

Villagers are the single most expensive entity in Minecraft. Each villager runs pathfinding AI, commerce state machines, and gossip updates. If your server has a large trading hall with 50+ villagers, that's a significant lag source.

In paper-world-defaults.yml:

# Villager optimizations
entity-activation-range:
  tick-inactive-villagers: false   # Villagers > activation range tick at 1/20 speed

villager:
  brain-ticks: 2   # Villager AI runs every 2 ticks instead of 1
  search-radius:
    acquire-poi: 48    # Default 48
    nearest-bed: 48    # Reduce if villagers can't find beds (cosmetic issue)

πŸ”Œ Plugin Audit β€” Common Lag Offenders

Plugins can cause lag in non-obvious ways. Here's a list of common patterns that cause performance issues:

🚨 High-Risk Plugin Patterns:

How to identify the offending plugin with Spark

In the Spark flamegraph, plugin method calls show as co.aikar.timings.PluginTimingsTask or the plugin's own package name. Look for plugin-named classes consuming >5% of server time.

Also run Paper's built-in timings:

/timings report

This generates a web report showing exactly how much time each plugin's event listeners are consuming per second. Sort by "total time" to find the worst offenders.

βœ… Quick Optimization Checklist

Before opening to players: Ongoing monitoring:

πŸš€ Want a Server Pre-Configured for Performance?

OliveerF Network servers run Paper 1.21 with Aikar flags, optimal Paper config, and Chunky pre-generation already set up. Free tier available.

View Hosting Plans