"The game lags" means nothing useful for troubleshooting. Before you can fix the problem, you need to know which problem you have — because the causes and solutions are completely different.

This guide covers all three types of Minecraft performance problems, how to identify which one you have, and the ranked fixes for each. Version-pinned to 1.21.4 Java Edition.

Identify your problem type first

Type 1: FPS drops

Symptoms: The screen feels choppy. The FPS counter drops (F3 shows a low number). Turning around fast causes a stutter. Entering a new area causes a freeze until chunks load.

Cause: Your CPU or GPU can't process and render frames fast enough.

Debug: Press F3. Look at the FPS number top-left. If it drops below 60 (or below your monitor's refresh rate) under load, this is your problem.

Type 2: TPS lag / server lag

Symptoms: FPS is fine (60+), but the world feels slow. Blocks take a second to break after the animation completes. Mobs teleport or rubber-band. Clocks and farms run slower than expected. Other players complain too.

Cause: The server simulation (even in single-player, "the server" is the internal server thread) can't process a tick within its 50ms budget. Ticks get queued, the game runs slower than real time.

Debug: Press F3. Look at the "TPS" field or install Spark and run /spark tps. A healthy server runs at 20 TPS. If you see 15 or below, this is Type 2.

Type 3: Network latency (multiplayer only)

Symptoms: FPS and TPS are both fine. But actions feel delayed only for you. Other players don't complain. Ping is high.

Cause: Packets from your client to the server are taking too long.

Debug: Press F3. Look at "Latency" or check the multiplayer tab. Over 150ms feels bad; over 300ms is unplayable.


Fixes for Type 1: FPS drops and stutters

Install the performance mod stack

The single highest-impact action. Sodium alone typically doubles or triples FPS on the same hardware.

Install in order:

  1. Sodium 0.6.7 — render pipeline replacement
  2. Lithium 0.13.x — game logic (also helps Type 2)
  3. FerriteCore 7.x — memory reduction (fixes GC stutter)
  4. EntityCulling 1.21.4 — skips rendering occluded entities

Full explanation in the complete Fabric performance mod stack guide.

Allocate the right amount of RAM — not too much

Most players either allocate too little (game thrashes with GC pauses) or too much (the garbage collector has to sweep enormous heaps, causing multi-second freezes).

Recommended allocations for 1.21.4:

Setup Recommended RAM Notes
Vanilla / few mods 3–4 GB More causes GC pause problems
Mid-size modpack (50–100 mods) 5–6 GB Sweet spot
Large modpack (200+ mods) 6–8 GB Don't go over 8 without G1GC tuning
Kitchen sink (400+ mods) 8–12 GB Requires JVM flags

In the Minecraft launcher: Installations → Edit → More Options → JVM Arguments. Change the -Xmx value.

-Xmx4G   # 4 GB max heap — good for vanilla
-Xmx6G   # 6 GB — good for typical modpacks

Use optimized JVM flags

The default Java GC settings are not tuned for Minecraft's allocation pattern. These flags significantly reduce GC pauses:

-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

These are the Aikar flags, the community standard for Minecraft JVM tuning. Add them to your JVM arguments in the launcher, replacing the default -XX:+UnlockExperimentalVMOptions if present.

Shader compile stutters — a special case

If you're running shaders with Iris and you see a 1–2 second freeze the first time you look at a new area, this is shader program compilation — OpenGL compiling shader code on your GPU when new geometry enters view.

Fixes:

  • Iris shader cache — Iris caches compiled shaders. The first session stutters; subsequent sessions don't. Wait it out.
  • Use a lighter shader pack — Complementary Unbound is lighter than Complementary Reimagined; BSL is heavier than either.
  • Enable async shader compilation in Sodium's settings (Sodium Extra → Video Settings → Performance → Async Shader Compilation)

There is no complete fix for compile stutters on first load. It is a limitation of the OpenGL shader compilation model.

Reduce render distance

The nuclear option that always works. Drop render distance until FPS is stable, then raise it slowly. Each render-distance step adds a ring of chunks to render, scaling roughly as the square. Going from 16 to 12 chunks cuts rendered chunk count by ~44%.

In single-player, also reduce simulation distance independently — you can render far without simulating far.


Fixes for Type 2: TPS lag (server-side)

Profile before you tune

You cannot fix what you haven't measured. Install Spark and run:

/spark profiler start

Let it run for 2 minutes with your farm and players active, then:

/spark profiler stop

Spark generates a URL with a breakdown of where tick time is going. The top entries are your problem. Common culprits:

  • Mob AI — too many entities, complex pathfinding
  • Hopper logic — hoppers check their target every tick even when empty
  • Chunk generation — ungenerated terrain being loaded by exploring players
  • Redstone — large clocks or complex circuits updating every tick

Pre-generate the world with Chunky

Chunk generation is CPU-intensive and synchronous in vanilla — when a player explores new terrain, the server spends tick time generating those chunks. On a fresh server, this causes TPS drops whenever players explore.

Install Chunky and pre-generate before launching to players:

/chunky center 0 0
/chunky radius 5000
/chunky start

This generates a 10,000-block diameter region ahead of time. It runs in the background over several hours. Players can join while it runs; TPS stabilizes once they stop hitting the border of pre-generated terrain.

Reduce entity count

High entity counts are the most common TPS killer. Minecraft updates every entity AI every tick. 500 animals in your base is 500 AI calculations per tick.

Vanilla commands:

/kill @e[type=item]              # kill all dropped items
/kill @e[type=experience_orb]   # kill all XP orbs

Long-term solutions:

  • Set maxEntityCramming gamerule lower (default 24 — entities above this per block take suffocation damage and die)
  • Breed animals only as needed, not indefinitely
  • Use hopper-minecarts instead of hoppers for item collection — hopper-minecarts check less frequently

Reduce hopper activity

Hoppers check their target every tick when active. A large hopper chain where nothing is being processed wastes tick time on empty checks.

Solutions:

  • Comparator lock hoppers when empty — a comparator reading an empty hopper outputs 0, which can lock adjacent hoppers
  • Use Chunk activity — group hoppers into systems that are only active when the farm is running
  • Replace intermediate hoppers with hopper-minecarts — minecarts check less often in vanilla

Raise simulation distance carefully

Counterintuitively, raising simulation distance can increase TPS problems (more chunks ticking = more entities simulating), but on a server where players are close together, having a lower simulation distance that matches actual player spread avoids loading unnecessary chunks.

Set simulation distance just high enough to cover player activity areas, not more:

simulation-distance=8   # server.properties

Install Paper (multiplayer servers only)

If you run a multiplayer server, switching from vanilla or Fabric to Paper gives significant TPS improvements at the server level — multi-threaded chunk saving, better hopper handling, configurable entity activation ranges, async world saving. Paper's performance is substantially better than vanilla's for loaded servers.

Note: Paper-specific optimizations are separate from Fabric mod-based optimizations. They're compatible with Fabric through Geyser/special builds, but for a pure Fabric server, Lithium + Spark is the standard path.


Fixes for Type 3: Network latency

Check your connection first

Before adjusting Minecraft settings:

  • Run a speed test to your game server's region
  • Check for packet loss: ping -n 20 <server-ip> (Windows) or ping -c 20 <server-ip> (Linux/Mac)
  • If you're on Wi-Fi, switch to ethernet — Wi-Fi introduces variable latency that feels like lag even at fast speeds

Reduce network load in-game

  • Lower render distance — fewer chunks to load means fewer packets during movement
  • Disable streaming textures from resource packs with high-resolution assets
  • Install Krypton (Fabric) — it reduces packet overhead on the server side, which lowers the data per tick sent to each client

Server-side network settings

In server.properties:

network-compression-threshold=256   # compress packets over 256 bytes (default is fine for most)

For high-latency connections (100ms+), raising this threshold can reduce compression CPU overhead at the cost of larger packets — test both directions for your specific connection.


Diagnostic cheat sheet

Symptom Check Likely cause First fix
Choppy / low FPS F3 → FPS number GPU/CPU overloaded Install Sodium
Smooth FPS, slow world F3 → TPS / Spark Server TPS drop Run Spark profiler
1–2 second freeze on new areas Timing: first look at area Shader compile stutter Enable async shader compile
Multi-second random freeze Timing: irregular, GC-like GC pause Fix RAM allocation + JVM flags
Lag only for me on multiplayer F3 → Latency Network Check ping, switch to ethernet
Farm running slow Check TPS + /forceload query Entity AI or chunk loading Spark → reduce entities

Sources & further reading: