How to Use Spark to Find Lag on Your Minecraft Server
Complete guide to installing and using Spark profiler to diagnose lag, read flame graphs, check memory and GC, and pinpoint which plugin or system is slowing your server.
Why Spark Is Essential for Server Admins
Spark is a performance profiler built specifically for Minecraft servers. It tells you exactly where your server is spending its time each tick, how memory is being used, and what the garbage collector is doing. Without Spark, diagnosing lag is guesswork. With it, you can look at a flame graph and say "LuckPerms is taking 12ms per tick because of a misconfigured context calculation" or "entity ticking in the nether is consuming 60% of each tick because someone built a piglin farm with 400 entities." That level of specificity is what separates a server admin who fixes lag from one who just keeps restarting and hoping.
Spark works on Paper, Spigot, Purpur, Fabric, Forge, NeoForge, BungeeCord, Velocity, and even the vanilla server. It is free, open-source, and used by the Paper development team themselves.
Installing Spark
Download the Spark plugin JAR from spark.lucko.me and drop it into your plugins/ folder (or mods/ for Fabric/Forge). Restart the server. Spark registers its commands immediately. You need the spark permission node or OP status to use Spark commands. If you use LuckPerms, grant the spark permission to your admin group.
Verify the install by running /spark in-game or in the console. You should see the Spark help menu listing all available subcommands.
Using the Profiler
The profiler is Spark's most powerful tool. It samples what the server is doing thousands of times per second and builds a statistical picture of where time is being spent.
Starting a profile
Run /spark profiler start to begin recording. Let it run for at least 5 minutes during normal server activity. If you are investigating a specific lag event, start the profiler before the event and stop it after. For TPS problems, profile during peak player count.
When you are done, run /spark profiler stop. Spark uploads the data to its viewer and gives you a URL. Click it to open the flame graph in your browser.
You can also target specific threads. To profile only the main server thread (which is almost always what you want for TPS issues), run /spark profiler start --thread Server thread.
Reading flame graphs
The flame graph looks intimidating at first but it follows a simple principle: width equals time. Each bar represents a method (function) in the code. The wider the bar, the more time was spent in that method. Bars are stacked vertically to show the call chain: the method at the top called the method below it.
Start from the bottom. You will see the main server tick method, which calls everything else. Scan upward and look for wide bars. These are your bottlenecks. Hover over any bar to see the exact percentage of total tick time it consumed.
The key sections to look for:
- Entity ticking, Shows up as
tickEntitiesorentityTick. If this is more than 30% of the tick, you have too many entities somewhere. Expand the bar to see which entity types are responsible. - Chunk loading / generation, Appears as
chunkLoad,ChunkGenerator, or similar. If this is dominant, you need to pre-generate your world. - Plugin handlers, Look for your plugin names in the call stack. If a plugin's event handler is consuming a significant portion of tick time, that plugin is your problem. Common offenders include protection plugins checking permissions on every block event, chat plugins formatting messages synchronously, and scoreboard plugins updating every tick.
- Tile entity ticking, Hoppers, furnaces, brewing stands, and modded machines all tick as tile entities. If
tickBlockEntitiesis taking too long, you have too many active tile entities. Hoppers are usually the worst offender.
Profiler flags for specific investigations
Use /spark profiler start --only-ticks-over 50 to only sample ticks that took longer than 50ms (i.e., ticks that caused TPS to drop). This filters out all the healthy ticks and shows you only what happens during lag spikes. It is extremely useful for intermittent lag.
Checking TPS and Tick Timing
Run /spark tps for a quick overview of your server's tick rate. Spark shows the current TPS, the average tick duration, and a percentile breakdown. The 95th percentile number is the most important one: it tells you that 95% of your ticks completed within that duration. If your 95th percentile is 48ms, your server is running well. If it is 75ms, you have a problem even if the average looks fine.
For a quick visual, /spark tickmonitor starts a real-time feed in your console showing the duration of every tick that exceeds a threshold. Run /spark tickmonitor --threshold 50 to only see ticks that exceed the 50ms budget. This is great for catching intermittent lag.
Memory and Garbage Collection
Run /spark health to see a snapshot of memory usage, CPU usage, and disk I/O. The memory section shows heap usage, which tells you how much of your allocated RAM is actually in use. If your heap is consistently above 85%, you either need more RAM or you have a memory leak in a plugin.
For garbage collection details, use /spark gc. This shows the number of GC pauses, their average duration, and the total time spent in GC. If you see frequent long pauses (over 100ms), your JVM flags need tuning. If GC pauses are short but extremely frequent, you may be under-allocated on RAM.
Spark can also generate a heap dump with /spark heapdump. This creates a file you can open in VisualVM or Eclipse MAT to inspect exactly which objects are consuming memory. This is advanced, but it is the only way to diagnose memory leaks in plugins.
Real Examples of Common Lag Patterns
Here is what specific problems look like in Spark so you know what to look for:
Example: Entity ticking consuming 60% of tick
The flame graph shows a huge tickEntities bar. Expanding it reveals Villager.tick taking 40% alone. The cause: a player built a villager trading hall with 200 villagers in a single chunk. Each villager runs pathfinding, gossip updates, and trade restock logic every tick. The fix: reduce villager count to 20-30, or use a plugin to limit villager AI when no player is actively trading.
Example: Plugin event handler blocking the main thread
A wide bar in the flame graph traces through PluginManager.callEvent into MyBankPlugin.onBlockBreak which calls MySQL.executeQuery. The plugin is running a synchronous database query on the main thread for every block break event. Every time a player breaks a block, the server waits for the database to respond before processing the next tick. The fix: replace the plugin, or ask the developer to use async database calls.
Example: Chunk generation spikes
The --only-ticks-over profile shows that nearly every slow tick involves ChunkGenerator and NoiseChunkGenerator. Players are exploring new terrain, and each new chunk takes 20-40ms to generate. On a tick that generates 3 chunks, total tick time exceeds 100ms. The fix: pre-generate with Chunky and set a world border.
Sharing Spark Results
When you stop a Spark profiler, the results are automatically uploaded to spark.lucko.me and you receive a URL. Share this URL in support channels, Discord servers, or with other admins. The viewer is interactive, anyone with the link can explore the flame graph, zoom into sections, and search for specific methods. You do not need to send raw files or screenshots.
If you are troubleshooting on a forum or asking for help, always include the Spark link. Server admins and developers can diagnose problems in minutes from a Spark profile that would take hours of guessing otherwise.
Need a server that handles all this? Astroworld Hosting runs NVMe SSD, Pterodactyl panel, and DDoS protection on every plan. See all features , plans start at €6.39/mo.