Define the slowdown before profiling
A useful profile begins with a specific server symptom. Write down what players experience, when it starts, how long it lasts and whether everyone is affected. Server tick lag usually appears as delayed block actions, slow mobs or movement snapping back for several players at once. High network latency and low client frame rate can feel similar, but a Paper CPU profile will not explain a player's graphics settings or an unstable route to the server.
Record a small baseline before changing anything: Paper and Java versions, player count, loaded worlds, recent changes, and the next expected slowdown. Paper's profiling guidance says the issue must be actively occurring for a profile to diagnose it. An empty-server capture cannot explain a stall that appears only during the evening event.
Choose one reproducible window. It might be players exploring new terrain, a farm switching on, an auction task running, a backup starting or a minigame resetting. Ask players not to introduce unrelated stress during the capture, and note the exact start and stop times. The broader checklist at /blog/minecraft-server-lag-fix-guide can help separate tick lag, ping and client FPS before you collect the wrong evidence.
- Describe one visible symptom and the players, world or scheduled task involved.
- Capture the live Paper, Java and plugin versions before making changes.
- Plan to profile while the slowdown is happening under representative load.
- Keep backups and a rollback point before changing plugins or world settings.
Confirm which spark installation you are using
Paper bundles spark starting with Paper 1.21, and PaperMC identifies it as the preferred profiler. On a current Paper server, run spark from the server console first. Console commands normally omit the leading slash; an authorized player uses /spark in game. If the command is missing, confirm that the service actually runs Paper and read the complete startup log before installing another JAR.
The profiler command requires the spark or spark.profiler permission. Give diagnostic access only to trusted administrators because the commands can create and upload detailed server reports. The console avoids in-game permission ambiguity; otherwise grant the narrow spark permission needed for the task instead of operator access.
Paper documents an override for administrators who deliberately need a newer standalone spark release than the bundled version: put the official spark plugin JAR in plugins and start Paper with the paper.preferSparkPlugin system property set to true. Treat that as a normal production plugin change—verify the source, back up, stage and restart. Do not add a second spark merely because a command was typed at the wrong proxy or backend.
- Use the backend Paper console, not a Velocity or BungeeCord console, for a Paper tick profile.
- Verify the reported Paper version and spark command before adding files.
- Limit spark permissions to trusted diagnostic operators.
- Prefer the bundled profiler unless a tested newer plugin is genuinely required.
Take a quick health baseline
Run spark tps to inspect tick rate and milliseconds per tick before the main capture. A normal Minecraft server targets 20 ticks per second, which requires average tick work to stay at or below 50 milliseconds. Look at the distribution rather than quoting only one instant. Median and percentile values help distinguish a consistently busy server from rare long ticks that disappear inside an average.
Use spark health show for a concise report, adding --memory or --network only when that context helps. CPU, memory, disk and network readings describe the environment; they do not identify which plugin method, entity task or world operation consumed the server thread.
Container and game-panel metrics need context. spark's documentation notes that CPU or memory values can be misreported in containerized environments because it receives data from Java and operating-system interfaces. Compare suspicious readings with the host or panel's cgroup-aware metrics. Do not upgrade RAM because one number is red, and do not dismiss tick lag because the whole-machine CPU percentage looks low while the main game thread is saturated.
- Record TPS, median and high-percentile MSPT during both normal and slow periods.
- Use health data as context, not as a substitute for a profiler trace.
- Corroborate container CPU, memory and disk readings with host-level metrics.
- Preserve the baseline so the eventual change can be compared fairly.
Capture the real workload
For a straightforward CPU investigation, run spark profiler start --timeout 600 while the problem is present. PaperMC uses this ten-minute example in its current profiling guide. spark stops automatically after 600 seconds and returns a viewer URL. If the useful event finishes early, run spark profiler stop; use spark profiler info to check status, or spark profiler cancel when the capture should be discarded without uploading a result.
Start shortly before the reproducible workload, then record player count, worlds, scheduled jobs and the minute when the symptom appeared. Normal activity can dilute one brief event, while an extremely short sample can overstate a moment that never repeats. Capture the problem plus enough surrounding behavior to interpret it.
The standard profile is usually the right first view of Paper's tick work. Use --thread * only when evidence points to work on other threads, because collecting every thread produces a larger, more complicated report. Use --alloc for memory-allocation pressure rather than ordinary CPU time. Do not combine advanced flags at random; each changes the question the profile answers, so keep the command and reason beside the report.
- Start a bounded capture: spark profiler start --timeout 600.
- Stop early with spark profiler stop when the complete event has already occurred.
- Record the workload and exact incident time alongside the returned report URL.
- Change thread or allocation modes only when the first evidence justifies it.
Isolate intermittent lag spikes
A rare long tick can disappear inside an otherwise healthy average. spark's tick monitor can announce ticks that cross a relative or absolute threshold. Run spark tickmonitor --threshold-tick 50 to observe ticks exceeding 50 milliseconds, then compare those messages with the in-game event and server log. Choose a threshold from the actual baseline; a noisy monitor set below normal tick time will create more messages without adding evidence.
Once a repeatable spike duration is known, start a filtered profile with spark profiler start --only-ticks-over followed by a threshold in milliseconds. The official lag-spike guide recommends choosing a value below the slow ticks you need to capture. This excludes ordinary ticks from the profiler samples and makes the expensive path easier to see. It does not fix the spike, and a threshold above the incident will produce an empty or misleading result.
Run the monitor first, then the filtered profile during the same workload. Compare the spike time with backups, map renders, world edits and player actions. If the event cannot be reproduced, monitor for a bounded diagnostic window rather than changing several plugins on suspicion.
- Measure the long ticks before choosing an only-ticks-over threshold.
- Set the filter below the slow event but above ordinary tick duration.
- Correlate each spike with the server log and actual player or scheduled activity.
- Repeat the same workload before treating one isolated sample as the cause.
Read the spark viewer from the top down
Open the returned URL and begin with the Server thread for normal Paper tick problems. Threads appear at 100 percent because each root represents all sampled time for that thread. Expand the path into the Minecraft server tick and follow children with relatively large percentages. Sleeping or parked time is normally healthy headroom, while time beneath the tick path represents work the server was performing.
Keep following the largest relevant branch until it identifies a meaningful source: world ticking, entities, block entities, chunk work, a CraftBukkit scheduler task or code owned by a plugin. The Sources view can group outgoing calls by plugin or mod; Flat view can surface expensive methods by total or self time; and Flame Graph width represents the sampled portion of time. Use these as different views of the same capture, not as three independent votes.
A wide node names where samples accumulated, not automatically what should be deleted. A permissions plugin may appear because another plugin calls it excessively, and world code may be expensive because one farm created an unusual entity workload. Expand callers and children, bookmark the important method, and share it with the responsible developer alongside reproduction steps and versions.
spark uploads normal profiler results to its configured content service and the viewer URL is designed to be shareable. Treat it as diagnostic data: review the report before posting it publicly and avoid attaching private logs, addresses or credentials. When uploading is unsuitable, the command reference provides spark profiler stop --save-to-file to store the profile under spark's configuration directory instead.
Change one cause and prove the result
Turn the hot path into the smallest reversible test. For an expensive plugin task, check the project's current configuration and release notes, reproduce on staging and ask the author with the report. For an entity or block workload, inspect the named world and activity before changing global limits. For chunk generation, compare the event with exploration or a planned generation job. A profile should narrow the experiment; it should not justify copying an unrelated optimization pack into production.
Apply one tested change, restart only when the software or setting requires it, and repeat the same player count and workload. Capture a second report of similar duration and compare MSPT plus the relevant branch. Success means the player-visible symptom improves and the expensive path shrinks without moving the cost into another critical task. Keep the before and after URLs, configuration diff and rollback instruction in the maintenance record.
If memory pressure is the real question, use an allocation profile or heap summary deliberately instead of reading retained memory from a CPU tree. Heap dumps are large sensitive server artifacts and should be created only with a defined storage, access and analysis plan. If network ping is the symptom, spark ping and host network data are more relevant than a tick profile. Match the tool to the question each time.
Continue measuring after the quiet test, because a real busy period may exercise paths staging missed. More practical server guides are collected at /blog. If a verified profile shows that the healthy workload has exceeded available compute, memory or storage, compare the documented plans at /pricing using the measured constraint rather than a generic player-count guess.
- Reproduce the hot path on staging before changing production data or plugins.
- Apply one reversible change and repeat the same profile window.
- Compare player symptoms, MSPT and the relevant branch before and after.
- Keep the evidence and rollback note for the next performance incident.
Frequently asked questions
Quick answers
Does Paper include the spark profiler?
Paper bundles spark starting with Paper 1.21 and recommends it for profiling. Confirm the live Paper version and use the backend console before installing a separate spark plugin.
How long should I run a spark profile?
Run long enough to capture the real slowdown. PaperMC's standard example uses a 600-second timeout, but a focused shorter capture can be better when the complete reproducible event has already occurred.
How do I find a Minecraft server lag spike with spark?
Measure slow ticks with spark tickmonitor, then profile with --only-ticks-over set below the spike duration and above ordinary tick time. Reproduce the same event and correlate it with logs.
How do I read a spark profiler report?
Start with the Server thread, expand the tick path and follow relatively large percentages toward a world task, entity workload, scheduler or plugin source. Inspect callers before blaming the final named component.
Can a spark profile tell me how much RAM to add?
A normal CPU profile shows sampled execution time, not a RAM recommendation. Use health data, allocation profiling or a heap summary for memory pressure, then verify the container or host metrics before changing capacity.
