When a FiveM server lags, the cause is almost always one or two resources, and you find them with three tools: resmon 1 in the client's F8 console for what scripts cost on each player's machine, profiler record in the server console for what they cost on the server's main thread, and the hitch warnings and txAdmin tick chart that tell you when it is happening. More memory rarely changes anything, and more cores change little, because the work that matters runs on one thread. This guide covers how to read each tool, what the numbers mean, the code patterns that keep turning up in the results, and the order to work in so that you fix the cause rather than buy your way around it.
Two kinds of lag, and why it matters which one you have#
Players say "the server is lagging" about two different problems, and they need different tools.
Client-side cost is frame time on the player's own PC. Every client script runs inside the game's frame. A resource that does too much on every frame drops everyone's FPS, but only while that resource is active for them. Symptoms: low or uneven FPS, worse in certain places (near a job marker, inside an interior with a script running), unaffected by how many people are online. The server can be perfectly healthy while this happens.
Server-side cost is time on FXServer's main thread. Server scripts, event handlers and timers all run there in sequence, so one slow handler delays everything queued behind it - including the processing that keeps players in sync. Symptoms: rubber-banding, vehicles jumping, doors and inventories reacting late, / commands taking a second to answer, everyone affected at once. FPS is fine.
There is a third thing that looks like both and is neither: the network. Packet loss between one player and the server gives that player rubber-banding while everyone else is happy. If only one person complains, start with latency, jitter and packet loss, not with your scripts.
| Symptom | Likely layer | First tool |
|---|---|---|
| Low FPS in one area, everyone online or not | Client script | resmon 1 |
| Everyone rubber-bands at the same moment | Server main thread | Hitch warnings, profiler |
| One player rubber-bands, others fine | Their network | Ping, traceroute |
| Long first join, then fine | Streaming assets | Size of stream folders |
| Slow after a day of uptime, fine after restart | Leak or entity build-up | Memory over time |
resmon: what each resource costs a client#
Open the F8 console in game and type:
resmon 1resmon 0 closes it again. The overlay lists every running resource with the CPU time it used per frame in milliseconds and the memory it holds on the client. Sort by CPU time and watch it for a minute while doing ordinary things - walking around, getting in a car, opening the inventory - because cost is often conditional on what the player is doing.
How to read the numbers: at 60 FPS the game has about 16.7 ms to produce a frame, and the game itself needs most of that. A resource that is idle - nothing on screen, player nowhere near its feature - should show 0.00 or 0.01 ms. A HUD, a minimap or a voice resource that genuinely draws every frame might sit at a few hundredths. Anything idling above about 0.10 ms is doing work it does not need to, and anything regularly above 0.5 ms is a real problem on its own. Ten resources at 0.2 ms each is two milliseconds of every frame gone before the player has done anything.
| resmon CPU while idle | Verdict |
|---|---|
0.00 - 0.02 ms | Fine |
0.03 - 0.10 ms | Acceptable for a HUD or anything that draws |
0.10 - 0.50 ms | Wasteful - look at its loops |
Above 0.50 ms | Fix or remove it |
Memory in resmon is the Lua heap for each resource. A value that climbs steadily over half an hour and never drops back is a leak - tables being appended to and never cleared, usually a cache keyed by something that keeps changing. A large but flat number is just a resource that holds a lot of data and is less interesting.
The limitation is that resmon only measures client scripts. A resource can be nearly free on the client and still be the one destroying your server, so do not stop here.
The server side: hitch warnings and the profiler#
FXServer prints a warning when one of its threads takes far longer than it should between ticks:
[ citizen-server-impl] server thread hitch warning: timer interval of 412 milliseconds[ citizen-server-impl] sync thread hitch warning: timer interval of 187 milliseconds[ citizen-server-impl] network thread hitch warning: timer interval of 158 millisecondsRead them by thread. The server thread is where your Lua, JavaScript and C# resources run; hitches there are almost always a script. The sync thread handles OneSync state - entities, their positions and who owns them - and hitches there usually mean too many entities or something spamming state changes. The network thread sends and receives packets; hitches there on a host that is otherwise fine point at very large event payloads or an overloaded machine.
An occasional hitch at startup or when a large resource restarts is normal. A steady trickle while players are online is the thing to fix. Note the time of each one and what was happening in game - a hitch every time someone opens a shop is already half the diagnosis. Reading the console covers separating these from the rest of the output.
To find out which resource caused them, use the built-in profiler from the server console:
profiler record 500This records the next 500 server ticks. When it finishes, run profiler view and FXServer prints a link that opens the recording in a Chrome-based timeline viewer. profiler save writes the recording to a file instead, which is useful when the console is remote and you want to look at it later or send it to whoever wrote the resource. The same profiler commands work in a client's F8 console, which is how you go deeper than resmon on a single client.
In the timeline, each tick is a block, and inside it you can see which resource and which function used the time. You are looking for the wide bars: one resource's handler taking tens of milliseconds while everything else takes fractions of one. Record while the problem is happening - a profile of a quiet server at 4am proves nothing. If the lag comes in spikes, record more ticks so the spike falls inside the window.
txAdmin's performance chart#
txAdmin keeps a running histogram of tick times for FXServer's threads and draws it on its dashboard. Recent versions let you switch between the main, sync and network threads. Each column is a time slice; the colours show what fraction of ticks fell into each duration bucket.
A healthy server spends nearly all of its ticks in the fastest bucket, all day. What you are looking for is the tail: a small, steady fraction of slow ticks that appears at certain hours or after a certain uptime. That shape is what players feel as periodic stutter rather than constant lag, and it tells you two useful things without opening a profiler - when it happens (correlate with player count and with what was going on in game) and whether it is getting worse over uptime, which points at a leak or entity build-up rather than one expensive handler.
txAdmin also restarts a server whose main thread stops responding entirely. If that keeps happening, the profiler is the next step; raising the hang timeout just lengthens the outage. The broader setup of txAdmin is in FiveM server setup with txAdmin.
The code patterns that show up every time#
Profile enough FiveM servers and the same handful of mistakes account for most of the time spent.
Loops that run every frame for no reason
Wait(0) means "run again next frame". It is correct for a loop that draws something every frame and wrong for almost everything else. The common case is a marker or interaction point checked every frame while the player is on the other side of the map:
-- Costs CPU on every frame, everywhere on the mapCreateThread(function() while true do Wait(0) local coords = GetEntityCoords(PlayerPedId()) if #(coords - shopCoords) < 2.0 then DrawText3D(shopCoords, "[E] Open shop") end endend)The fix is to sleep in proportion to distance, and only drop to every frame when the player is close enough for it to matter:
CreateThread(function() while true do local sleep = 1000 local coords = GetEntityCoords(PlayerPedId()) local dist = #(coords - shopCoords) if dist < 20.0 then sleep = 0 if dist < 2.0 then DrawText3D(shopCoords, "[E] Open shop") end end Wait(sleep) endend)That one change takes a resource from a permanent 0.1-0.3 ms to 0.00 for everyone not standing near a shop. Libraries such as ox_lib provide point and zone helpers that do this for you; using them is better than hand-rolling the same loop in forty resources.
Distance checks done the slow way
#(a - b) on two vector3 values is a pure Lua calculation and very cheap. GetDistanceBetweenCoords is a native call with marshalling overhead, and older resources call it hundreds of times a frame. Replacing it is a mechanical change with a measurable result.
Server handlers that do too much
On the server, the equivalent mistakes are a loop over every player with a database query inside it, a SetTimeout chain that fires more often than the state it represents changes, and handlers that json.encode a large table on every call. oxmysql is asynchronous, so a slow query does not freeze the thread by itself, but a handler that issues fifty of them per event will - and the queue of callbacks returning later lands on the main thread too. Setting mysql_slow_query_warning makes oxmysql print every query over the threshold; the database side is covered in FiveM databases and oxmysql.
Broadcasting too much
TriggerClientEvent('name', -1, data) sends to every player. Doing that once a second with a large table - a full job roster, every player's money - costs network thread time and client time on every machine. Send only what changed, only to the players who need it, and prefer state bags for values that many clients read but few write.
A workflow that finds it in an evening#
- Confirm the layer. Ask three players whether their FPS dropped or whether things rubber-banded. Check the console for hitch warnings at the times they report.
- Client side: have one player run
resmon 1and screenshot it while idle in the city and again at the place it lags. Note every resource over0.1 ms. - Server side: run
profiler record 500during peak hours while the lag is present, thenprofiler view. Note the widest resources. - Bisect what you cannot read. If the profile points at a framework core that dozens of resources call into, stop half of the non-essential resources (
stop namein the console), watch the hitches and the txAdmin chart for fifteen minutes, then bring them back. Repeat on the half that mattered. - Fix or replace. Most fixes are the loop patterns above. Escrowed resources you cannot edit go back to their author with your profile attached, or get replaced.
- Re-measure. Same conditions, same commands. If the number did not move, the change did not matter, whatever the forum post promised.
Do this before you change plan. On a server with a CPU-bound main thread, more memory does nothing at all and a bigger CPU share helps only if the console's CPU graph shows you are actually sitting at the limit. CPU vs RAM for game servers is the longer version of that argument.
What the machine contributes#
Code is the usual cause, but not the only one, and it is worth knowing what the hardware side looks like so you can rule it in or out.
| Resource | What it affects | Sign it is the limit |
|---|---|---|
| CPU share | Tick time on every thread | Console CPU graph flat at the plan's limit |
| Memory | Nothing until it runs out | Memory graph climbing toward the limit over uptime |
| Disk | Startup, resource restarts, streaming | Slow boot, slow first joins |
| Network | Joins and sync | Network thread hitches with low CPU |
- CPU share. Server work is dominated by the main thread, so clock speed matters more than core count. A second core still helps: the sync and network threads, asset serving and the database client do run elsewhere. If the CPU graph sits at the plan's ceiling at peak, ticks stretch and the hitch warnings follow.
- Memory. Memory tracks the number of resources and what they hold, not the number of players. It is rarely the cause of lag; when it runs out, the server stops, which is a different problem.
- Entities. With OneSync, every vehicle, ped and object the server tracks costs sync time. Ambient population, abandoned vehicles that nobody deletes and props spawned by scripts and never cleaned up all accumulate. OneSync and player slots covers population settings and culling.
- Streamed assets. Large vehicle and map packs cost disk, bandwidth and client memory, not server CPU. A slow first join is a download problem; MLOs, maps and streaming assets deals with it.
On RE:NODE the console draws memory, CPU and disk against the plan's limits, so you can see which one you are actually against before deciding anything. CPU is a hard throttle to the share you bought: a server pinned at 100% gets slower, and it is never suspended for it. If memory reaches the limit, the container is stopped and restarted clean rather than left to swap - txAdmin and your scheduled restarts carry on from there.
Uptime, leaks and scheduled restarts#
FXServer and the frameworks on it degrade over long uptimes. Lua heaps grow, entity counts drift upward, caches fill. A server that runs well for the first six hours and stutters by the second evening is showing build-up, not a single expensive handler, and the profiler will show many resources each slightly slower rather than one wide bar.
The honest fixes are to find the resource whose memory climbs in resmon or in its own logging, and to restart on a schedule while you look. A restart every six to twelve hours, announced in game a few minutes beforehand, is normal practice on roleplay servers; txAdmin's scheduler does the announcement and the restart, and the reasoning about picking the hour is in restart schedules that help. Before each scheduled restart is also the right moment for a database backup, because characters and money live there.
A restart is not a fix for a leak. It is a ceiling on how bad the leak can get. Keep looking for the resource.
Troubleshooting#
resmon shows nothing expensive, but players still rubber-band. It is the server or the network. Check for hitch warnings during the complaints and run the profiler.
The profiler shows one framework resource using most of the time. The framework is usually doing work on behalf of other resources - callbacks, item use, player data lookups. Look one level down in the timeline at which handlers call into it, or bisect the resources that depend on it.
Hitches every few minutes, regular as a clock. Something on a timer: an autosave that writes every player at once, a payroll loop, a vehicle persistence job. Stagger the work across players instead of doing it all on one tick.
Lag only during the first minutes after a restart. Resources loading data, everyone rejoining at once and downloading assets. It settles; if it does not, a resource is doing a large synchronous load on start.
Lag gets worse every day until a restart. A leak or entity build-up. Watch resmon memory and the sync thread over uptime.
One resource is expensive and escrowed. You cannot edit it. Send the author your profile and resmon screenshot. If it is not fixed, replacing it is cheaper than building a server around it.
FAQ#
What is a good resmon value for a FiveM resource?
When idle, 0.00 to 0.02 ms. Resources that draw every frame, such as HUDs, can reasonably sit a little higher. A resource that idles above 0.1 ms is wasting frame time, and one that regularly passes 0.5 ms is a problem on its own.
Does resmon show server-side performance?
No. resmon measures client scripts on the machine where you run it. For the server, use the hitch warnings in the console, profiler record and profiler view, and txAdmin's tick chart.
Will a bigger plan fix FiveM lag?
Only if the console shows the CPU sitting at the plan's limit at peak. Most FiveM lag is one or two resources blocking the main thread, and more memory or a higher limit leaves that exactly as it is. Profile first, then decide.
What does "server thread hitch warning" mean?
The server's main thread, where resources run, took far longer than normal between ticks - the number is how long. A few at startup are harmless; a steady stream while people play means a resource is blocking the thread and should be found with the profiler.
Why does my server get slower the longer it runs?
Usually memory growing in a leaking resource or entities accumulating without cleanup. Scheduled restarts cap the damage, but the cause is still there; watch memory per resource over time to find it.
Is Wait(0) always bad?
No. It is correct for anything that has to happen every frame, such as drawing text or a marker the player is looking at. It is wrong in a loop that only needs to react a few times a second, which describes most loops that use it.




Comments
Completely anonymous: no account, no email, no cookie. We store the name you type, the text and the time - nothing else. Links are limited and markup is not rendered.