8 min read

How to Use the Spark Profiler to Find What's Lagging Your Server

Install the spark profiler, run /spark profiler during the lag, then read the call tree to name the exact plugin, entity, or task eating your tick time.

How to Use the Spark Profiler to Find What's Lagging Your Server

When your server is lagging, the fastest way to stop guessing is spark. Install it, run /spark profiler start while the lag is actually happening, then /spark profiler stop to get a share link. That link opens an interactive report that names the exact plugin, entity, or scheduled task eating your tick time. No more changing settings on a hunch and hoping the numbers move.

spark is a sampling profiler, which means it periodically snapshots the main thread's stack instead of instrumenting every single call. The overhead is low enough that it's safe to run on a live server with players online, and that's exactly the point: you want to catch the lag under real load, not on an empty server where nothing is happening. This is owner-side work on a server you control (Paper, Spigot, or Purpur as a plugin; Fabric or Forge as a mod). A regular player can't run it on someone else's server.

The rest of this is about installing spark, getting a quick read, running the profiler at the right moment, and — the part that actually matters — reading the report so you come away with a name instead of a guess.

Install spark and confirm it's running

spark ships as a plugin or a mod. Grab it from Modrinth or Hangar, drop it in your plugins folder (or mods on Fabric/Forge), and restart. Plenty of hosts bundle it already or offer a one-click install from their panel, so check there first before you upload anything. It also runs on proxies like Velocity and BungeeCord if that's where your lag lives.

Confirm it loaded by running /spark tps in-game or from the console. spark commands need op or the spark permission, so if nothing happens, that's usually why. If you get a readout back, you're set.

One thing worth stating plainly: the old /timings command is done. Paper removed timings from recent builds, and Paper's own documentation now points you at spark instead. If a guide tells you to run /timings paste, it's out of date — spark is the tool.

Get a fast read first with /spark tps and /spark health

Before you profile anything, get your bearings. /spark tps shows TPS and MSPT side by side, each with the min, median, 95th percentile, and max, color-coded green, amber, and red. The number that matters here is the 95th-percentile MSPT, not the average. Averages hide the spikes; the 95th percentile tells you what your worst regular ticks look like, and that's where lag lives. If you want the full grounding on why, what TPS and MSPT actually mean covers it — the short version is that MSPT is the cause and TPS is the symptom. Each tick gets a 50 ms budget (1000 ms divided by 20 ticks), and once a tick runs long it shoves the next one back, so 20.0 TPS is a hard ceiling you fall away from.

Then run /spark health (or its alias /spark healthreport) for the wider picture: CPU, memory, disk, and JVM/GC info. Add the --memory flag if you want more heap detail. This won't tell you which plugin is the problem, but it tells you what class of problem you're looking at. A maxed CPU points somewhere different than a starved heap, and both point somewhere different than ticks that are simply too heavy — and that shapes what you do next.

Run the profiler while the lag is happening

Timing is everything here. spark can only report on what it samples, so you have to profile during the lag, with players online. An empty, quiet server profiles nothing useful.

For steady, always-there lag, keep it simple:

/spark profiler start

Let it run two to five minutes under normal player load, then:

/spark profiler stop

For lag spikes — the server is mostly fine but stutters every so often — you don't want the report drowned in thousands of healthy ticks. Filter to only the bad ones:

/spark profiler start --only-ticks-over 70 --timeout 60

That records only ticks over 70 ms and auto-stops after 60 seconds. Bump the threshold to --only-ticks-over 100 if you're chasing bigger, rarer freezes. The --timeout flag just saves you from forgetting to stop it. There are a few more flags — --thread <name> to target a specific thread, --alloc to profile memory allocation instead of CPU time — but the two above cover most lag hunts. Run /spark in-game for the full help if you need the rest.

Read the share link: the call tree

When you stop the profiler, spark uploads the data and hands you a URL on the spark viewer at spark.lucko.me. Open it. This is not a wall of text — it's an interactive call tree (you can flip it to a flame graph), showing your tick time broken down by what consumed it.

The rule for reading it is comparative, not absolute: the widest, hottest branches are your biggest time sinks. Don't hunt for some magic "acceptable" percentage — there isn't one. You're looking for the branch that's clearly fatter than everything around it, then drilling into it until you hit a name. Expand the heavy branch, keep following the widest child, and you'll land on one of a few recognizable things:

  • A named plugin class. spark labels plugin sources, so if a branch traces down into com.someplugin.SomeTask, you've found your culprit. That plugin is doing too much work per tick, and the fix is to configure it down, update it, or pull it entirely.
  • An entity-ticking or mob-spawning branch. If the heavy work is entities being ticked, you've got an entity load problem, which is the single most common heavy slice on most servers. Don't tune configs blind — go read how to reduce entity and mob lag and apply the specific fixes there.
  • Chunk generation or loading. Wide chunk-work branches usually mean players exploring fresh terrain or something forcing chunk loads. This one comes and goes with player behavior.
  • A scheduled task on a timer. A repeating task that fires on an interval will show up as a periodic heavy branch — often a plugin doing a world scan or a save more aggressively than it should.

Spend your time here. The whole reason to run spark is that this screen turns "my server is lagging" into "this specific thing is eating 40% of my tick time," and that's a problem you can actually solve.

Rule out garbage collection with /spark gcmonitor

Not every freeze is a plugin. Sometimes the server locks up because the JVM paused everything to run garbage collection. To check, run /spark gcmonitor — it prints a message each time a GC event finishes. Play for a bit and watch: if your freezes line up with GC messages appearing, the problem isn't your plugins, it's your heap and JVM setup.

That's a completely different fix. GC pauses commonly run 200 to 500 ms, which is enough to feel like a lag spike, and the answer is tuning your flags rather than touching plugins. Start with the best Aikar JVM flags, which cover G1GC tuning and when ZGC on Java 21+ makes sense.

Turn the finding into a fix

The report named the thing. Now go fix that one thing, and only that thing — changing five settings at once means you won't know which one helped. If spark pointed at a plugin doing too much, that's a plugin decision. If it pointed at entities, chunks, or general tick weight, how to fix TPS lag spikes is the companion post that walks through what to actually change in spigot.yml, bukkit.yml, and paper-world-defaults.yml for each cause.

Then re-check /spark tps and confirm the 95th-percentile MSPT actually dropped. If the numbers didn't move, you fixed the wrong thing — profile again. A server that holds a steady tick rate is one people stay on instead of rage-quitting on a stutter.

FAQ

Where does the share link's data live, and does it expire?

When you stop the profiler, spark uploads the sample to bytebin and the viewer at spark.lucko.me reads it back. The data sits on lucko's public infrastructure, so treat the link as shareable — anyone with the URL can open your report, including the plugin names on your server. The uploads aren't guaranteed to live forever, so if a report matters, screenshot the call tree or save your own copy rather than relying on the link months later.

Can I profile the console or a headless server with no one in-game?

Yes. Every spark command runs from the server console, not just in-game chat, so you can start and stop the profiler over SSH or your host's console tab. The catch is the same one that applies everywhere: spark reports what it samples, so a headless server with no players online won't reproduce the lag you're hunting. Line the profiling window up with real activity either way.

Does spark work on the newest snapshot or my exact version?

Yes. spark tracks the server software's API, not the Minecraft version, so it's effectively version-agnostic across Paper, Spigot, Purpur, Fabric, and Forge builds — including the newest experimental snapshots. There's no version-specific patch to match; if the plugin or mod loads, it works.