You've allocated more RAM. You're using Paper. You've added Aikars flags to your startup script. And your server still stutters when more than ten players are online.
Here's the problem: you're guessing. RAM, Java flags, and server software are all valid levers — but pulling them randomly is like swapping car parts until the engine runs. You need diagnostics first. You need to see what's actually happening during each server tick.
That's what Spark does. It's a profiler: a tool that samples your server's CPU usage thousands of times per second and shows you exactly which code paths are taking the longest. Not "entities are causing lag" — you'll see net.minecraft.world.entity.ai.goal.RandomStrollGoal.canUse() taking 23% of your tick. That's a diagnosis you can act on.
This guide walks you through installing Spark, running a profile, reading the flame graph output, and translating what you find into fixes. By the end, you'll stop asking "is it plugins or entities?" and start knowing.
What Profiling Actually Measures
Before diving in, let's clear up what a profiler does and what it doesn't.
TPS vs MSPT
You've probably seen TPS — ticks per second. A Minecraft server runs 20 ticks per second when healthy. If it drops to 15, you're lagging.
But TPS tells you there's a problem, not what the problem is. MSPT — milliseconds per tick — is more useful. Each tick has a 50ms budget (1000ms / 20 ticks = 50ms). If your server averages 42ms, you're fine. If it spikes to 120ms, those ticks are taking more than twice as long as they should, and TPS drops to compensate.
Spark measures what's happening inside those milliseconds.
CPU Sampling
Spark doesn't slow your server down or log every method call. It uses sampling: many times per second, it asks "where is the server right now?" and records the answer. After running for a few minutes, it assembles these samples into a statistical picture of where time is being spent.
This means Spark is safe to run on a live server with players. The sampling overhead is negligible.
Why RAM Is Rarely the Bottleneck
New admins throw RAM at lag problems because it feels intuitive — more memory, more room for stuff, faster server. But Minecraft servers are single-threaded. The main game loop runs on one core, and that core is the bottleneck.
Adding RAM beyond what's actually used doesn't speed up a tick. It just means the garbage collector has more to scan. For most servers, 4–10 GB is plenty. The CPU doing the ticking is what matters — and that's what Spark profiles.
This is why hardware with high single-threaded performance matters more than core count. It's also why hosting providers that use CPUs with large L3 caches (like the Ryzen X3D series) make a measurable difference for Minecraft specifically — the main tick loop fits in cache, avoiding slower RAM access.
If you're curious about RAM sizing for your specific setup, see the RAM guide.
Installing Spark
Spark comes in different packages depending on your server software. The plugin and mod are functionally identical — it's just how they're loaded.
Paper / Purpur (Plugin)
- Download the latest Spark release from the Spark website (spark.lucko.me/download) — grab the Bukkit version.
- Drop the
.jarfile into your server'splugins/folder. - Restart the server.
- Confirm it's loaded: run
/sparkin the console or in-game. You should see the help menu.
Fabric (Mod)
- Make sure Fabric Loader is installed on your server.
- Download the Spark Fabric version for your Minecraft version.
- Place the
.jarin themods/folder. - Restart the server.
- Run
/sparkto verify.
Forge (Mod)
- Download the Spark Forge version matching your Minecraft version.
- Place it in the
mods/folder. - Restart.
- Run
/spark.
Permissions
By default, only operators can use Spark commands. If you're using LuckPerms or another permission plugin, grant the spark permission node to admins:
spark.*
Or, for finer control:
| Permission | What It Allows |
|---|---|
spark.profiler | Start and stop CPU profiles |
spark.tps | View TPS and MSPT stats |
spark.health | View health reports |
spark.gc | View garbage collection stats |
For a full permissions setup guide, see the LuckPerms guide.
Running Your First Profile
Spark has several commands, but the one you care about most is /spark profiler.
Starting a Profile
In-game or in the console, run:
/spark profiler start
Spark begins sampling immediately. Let it run while the lag is happening. If your server hitches at noon when players are active, run the profile then — not at 3 AM when the server is empty.
A good profile duration is 2–5 minutes. Long enough to capture representative data, short enough to not bloat the output.
Stopping and Viewing
When you're ready, run:
/spark profiler stop
Spark compiles the samples and uploads the result to its viewer. You'll see a message with a URL like:
https://spark.lucko.me/abcd1234
Click it. This opens the Spark viewer — an interactive flame graph showing where your server spent CPU time.
The --only-ticks-over Flag
If your lag comes in spikes rather than constant slowdown, use:
/spark profiler start --only-ticks-over 50
This tells Spark to only sample ticks that exceeded 50ms (the healthy budget). You'll see exactly what made those bad ticks slow, without the noise of normal ticks diluting the data.
Reading Flame Graphs
The Spark viewer shows a flame graph. If you've never seen one, it looks intimidating. It's actually straightforward once you know how to read it.
What the Structure Means
Each horizontal bar is a method (a function in the server's code). The width of the bar represents how much time that method took — wider bars mean more time.
Bars stack vertically: if method A calls method B, B appears on top of A. The bottom of the flame graph is the server tick loop. As you move up, you drill into the specific code paths within that loop.
Colors
In Spark's default coloring:
- Green bars are Minecraft's own code (
net.minecraft...). - Yellow/orange bars are plugins or mods.
- Blue bars are Java library code or reflection.
If you see a wide yellow bar, that's a plugin or mod taking significant time. If you see a wide green bar, it's vanilla Minecraft — and you'll need to address it through config, not by removing a plugin.
Finding Hot Methods
Look for wide bars near the top of the graph. These are "hot" methods — the specific code taking the most time.
Click on a bar to zoom in. Spark shows you the percentage of total tick time that method consumed. If WorldServer.tick() is 100% (it always is — that's the main loop), but EntityGoalSelector.tick() under it is 40%, you now know that mob AI is eating 40% of your tick.
Thread Isolation
By default, Spark shows the main server thread. Use the dropdown in the viewer to switch threads. Most of your focus should be on the main thread — that's where the tick runs — but chunk loading and async tasks appear on other threads.
Common Culprits and What to Do
Once you've found the hot spots, here's what common ones mean and how to address them.
Chunk Generation
If you see time spent in ServerChunkCache or ChunkGenerator, your server is generating new terrain. This happens when players explore unloaded areas.
Fix: Pre-generate your world with Chunky before opening the server. See the Chunky guide. For Paper/Purpur, also ensure you're using the async chunk system (it's on by default in recent versions).
Entity AI
Methods like GoalSelector, PathfinderGoal, or Brain indicate mob AI calculations. With many mobs, this adds up.
Fix: Reduce mob caps in spigot.yml or paper-world-defaults.yml. Consider plugins like Mob Stacker that merge duplicate mobs. For a deeper dive, see the entity management guide.
Slow Plugins
If you see a plugin's namespace (e.g., com.exampleplugin.SomeClass) taking significant time, that plugin is the problem.
Fix options:
- Check for plugin updates — performance regressions are common in older versions.
- Audit plugin configs — some plugins have expensive features that can be disabled.
- Replace the plugin — find a lighter alternative or remove it.
- Contact the plugin author with your Spark profile link. Good developers will investigate.
Datapack Functions
If you're running datapacks with complex functions, you might see time in CommandFunction or CustomFunction.
Fix: Audit your datapacks. Remove or simplify ones that run every tick. The game rule maxCommandChainLength can limit runaway function loops, but the real fix is leaner datapacks.
Hopper and Redstone Tick
Hoppers and active redstone machines run calculations every tick. Large farms or sorting systems can become CPU sinks.
Fix:
- In
spigot.yml, increasehopper-transferandhopper-checkintervals to reduce hopper tick frequency. - Use water streams instead of hoppers where possible.
- For redstone, encourage players to build clock-based systems with longer intervals.
Plugin Reflection Abuse
If you see deep stacks in java.lang.reflect, a plugin is using reflection heavily at runtime. This is slow.
Fix: Report it to the plugin author. There's not much you can do from the config side — the plugin needs a rewrite.
Memory Profiling with Spark
CPU isn't the only thing Spark can analyze. If you suspect memory issues — or the garbage collector shows up in your CPU profile — Spark has tools for that too.
Heap Dump
Run:
/spark heapdump
This creates a snapshot of everything in memory. Spark uploads it to a viewer where you can see which objects are consuming the most RAM. If a plugin is leaking memory (holding references to objects it no longer needs), the heap dump will show it.
GC Monitoring
Run:
/spark gc
This shows garbage collection statistics: how often the GC runs and how long each pause takes. Frequent long pauses mean your server is thrashing — either you're using too much memory, or your GC settings need tuning.
If GC pauses show up as a significant portion of your tick time in the CPU profile, see the lag guide's section on Java flags for GC tuning recommendations.
When to Profile
Knowing how to profile is only useful if you profile at the right time.
Profile during lag. If your server only lags at peak hours, profile at peak hours. A profile from 4 AM with two players online will show you nothing useful about why the server stutters at 8 PM with thirty.
Profile after changes. Added a new plugin? Run a profile before and after. If MSPT jumps by 10ms, you know exactly what caused it.
Profile before blaming hardware. If you're considering upgrading your hosting plan or switching providers, profile first. If your profile shows a single plugin taking 60% of your tick, no amount of CPU upgrade will make that plugin efficient.
Quick Reference
| Command | What It Does |
|---|---|
/spark profiler start | Begin CPU sampling |
/spark profiler stop | End sampling and upload the profile |
/spark profiler start --only-ticks-over 50 | Only sample ticks exceeding 50ms |
/spark tps | Show current TPS and MSPT |
/spark health | Summary of CPU, memory, and disk |
/spark gc | Garbage collection statistics |
/spark heapdump | Upload a memory snapshot |
| Term | Meaning |
|---|---|
| TPS | Ticks per second (target: 20) |
| MSPT | Milliseconds per tick (target: under 50) |
| Flame graph | Visual representation of where CPU time is spent |
| Hot method | A function taking disproportionate CPU time |
| Sampling | Periodically checking what code is running (low overhead) |
Related Guides
- How to Fix Minecraft Server Lag — the general lag troubleshooting guide. Start here if you haven't already ruled out the basics.
- How to Pre-Generate Your World with Chunky — chunk generation is a top cause of lag spikes. Pre-generating solves it before players log in.
- What Hardware Does Your Modded Server Need? — if profiling reveals your CPU is maxed, this guide covers what hardware actually helps.
- Paper, Purpur, Fabric, or Forge? — different server software has different performance characteristics. Pick the right one.
- How to Control Mob Spawning and Entity Lag — if entities show up hot in your profile, this guide explains the spawning system and how to tune it.
Your server lag has a cause. It's not "just Minecraft being Minecraft." It's a specific method, in a specific plugin or in vanilla code, running too long during a specific phase of the tick loop.
Spark shows you where. Everything else — RAM, flags, view distance — is downstream of that diagnosis. Profile first, then fix. You'll stop guessing and start solving.
