How to Fix High Resmon in FiveM: Complete Optimization Guide (2026)
Learn how to read the resmon panel, identify resource-hungry scripts, and reduce server-side and client-side tick times. Practical techniques used by production servers with 200+ players.
What Is Resmon and Why It Matters
Resmon (short for resource monitor) is FiveM's built-in profiling tool. It measures how much CPU time each running resource consumes per server tick. Open it in-game by typing resmon 1 in the F8 console.
Every script on your server gets a slice of the tick budget. The server runs at roughly 64 ticks per second, which means each tick is about 15.6 ms. If your combined resource usage approaches or exceeds that budget, players experience rubber-banding, desync, and general lag.
In 2026, with servers running 150–300 players under OneSync Infinity, monitoring resmon is not optional — it is the single most important maintenance task a server owner can perform.
How to Read the Resmon Panel
When you enable resmon, you see a sorted list with columns:
| Column | Meaning | Good Value |
|---|---|---|
| Resource | Script name | — |
| CPU (ms) | Milliseconds per tick (client-side) | < 0.05 ms |
| Server (ms) | Milliseconds per tick (server-side) | < 0.10 ms |
Key rules of thumb:
- Any resource using more than 0.20 ms on the client deserves investigation.
- Any resource using more than 0.50 ms on the server is a problem.
- Resources showing 0.00 ms when idle are well-optimized — this is the standard that Jobs Creator by Alone Studios targets.
Top 5 Causes of High Resmon
1. Citizen.Wait(0) in Tick Loops
This is the single most common performance killer. A Citizen.Wait(0) inside a CreateThread loop means the code runs every single frame — 60+ times per second:
-- BAD: runs every frame even when player is far away
CreateThread(function()
while true do
Citizen.Wait(0)
local coords = GetEntityCoords(PlayerPedId())
-- heavy logic here every frame
end
end)
Fix: Use distance-based throttling. Run the heavy logic only when the player is nearby:
-- GOOD: adaptive wait based on distance
CreateThread(function()
while true do
local sleep = 1000
local coords = GetEntityCoords(PlayerPedId())
local dist = #(coords - targetCoords)
if dist < 10.0 then
sleep = 0
-- heavy logic only when close
elseif dist < 50.0 then
sleep = 500
end
Citizen.Wait(sleep)
end
end)
2. Unoptimized Native Calls
Some GTA natives are expensive. Calling GetClosestPed, GetGamePool, or raycast natives every frame wastes significant CPU:
-- BAD: GetGamePool allocates a new table every call
CreateThread(function()
while true do
Citizen.Wait(0)
for _, veh in ipairs(GetGamePool('CVehicle')) do
-- check something
end
end
end)
Fix: Cache the result and refresh on a longer interval:
local cachedVehicles = {}
CreateThread(function()
while true do
cachedVehicles = GetGamePool('CVehicle')
Citizen.Wait(2000) -- refresh every 2 seconds
end
end)
3. Client-Side Threads with Heavy Drawing
DrawMarker, DrawText3D, and other rendering natives must run at Wait(0) to appear smooth, but you should only call them when the player can actually see them. Always wrap draw calls inside a distance check.
4. Memory Leaks from Event Handlers
Registering events inside loops — or registering the same event multiple times — creates memory leaks that gradually increase resmon over time. Use a single registration per event and track state with variables.
5. Synchronous Database Queries
Running MySQL.Sync.fetchAll (or any blocking DB call) on the server main thread halts the entire tick until the query returns. This is the most common cause of sudden server-wide lag spikes.
Fix: Always use async variants: MySQL.query, MySQL.Async.fetchAll, or exports.oxmysql:query_async. See our SQL optimization guide for details.
Step-by-Step Resmon Optimization
Follow this process for every script with high resmon:
- Enable resmon — Type
resmon 1in the F8 console - Sort by CPU/Server time — Identify the top 5 offenders
- Read the source — Open the resource's client.lua or server.lua
- Find tick loops — Search for
CreateThreadandCitizen.Wait - Check wait values — Any
Wait(0)without a distance gate is suspect - Add distance checks — Wrap expensive logic in proximity conditions
- Cache expensive calls — Store results of natives and refresh on intervals
- Test and compare — Check resmon before and after your changes
Real-World Example: 0.15 ms to 0.01 ms
A common job script had this structure in its client loop:
CreateThread(function()
while true do
Citizen.Wait(0)
local ped = PlayerPedId()
local coords = GetEntityCoords(ped)
for _, marker in ipairs(Config.Markers) do
local dist = #(coords - marker.pos)
if dist < 50.0 then
DrawMarker(marker.type, marker.pos.x, marker.pos.y, marker.pos.z, ...)
end
if dist < 2.0 then
ShowHelpNotification(marker.label)
end
end
end
end)
Resmon: 0.15 ms (with 30 markers configured).
After optimization — splitting into two threads (one for drawing at Wait(0) only when nearby, one for distance scanning at Wait(500)): resmon dropped to 0.01 ms when idle and 0.04 ms when near markers.
This is exactly the approach used by Jobs Creator, which maintains 0.00 ms idle resmon regardless of how many jobs and markers are configured.
Tools for Monitoring Performance
| Tool | Purpose | How to Use |
|---|---|---|
| resmon 1 | Per-resource CPU usage | F8 console command |
| resmon 0 | Disable resmon overlay | F8 console command |
| profiler | Detailed frame profiling | profiler record 30 in F8 |
| txAdmin | Server-side resource stats | Web panel → Performance |
| hitch warnings | Server tick overruns | Appears in server console |
Common Mistakes to Avoid
- Removing Wait entirely — This freezes the game. Always include
Citizen.Waitin any loop. - Using Wait(1) thinking it is better than Wait(0) — In practice, both run every frame. Use
Wait(100)or higher for real throttling. - Blaming the framework — ESX and QBCore cores are well-optimized. High resmon almost always comes from third-party scripts, not the framework itself.
- Optimizing the wrong resource — Always check resmon data first. Don't waste time on a script using 0.01 ms when another uses 0.50 ms.
Checklist: Is Your Server Optimized?
- ⬜ All tick loops use distance-based
Citizen.Waitvalues - ⬜ No
GetGamePoolcalls running every frame - ⬜ DrawMarker calls are wrapped in proximity checks
- ⬜ All database queries use async methods
- ⬜ No duplicate event handler registrations
- ⬜ Top 5 resmon scripts are each under 0.10 ms
- ⬜ Server tick rate stays above 60 tps during peak hours
- ⬜ All job-related logic is handled by an optimized system like Jobs Creator
Need Help?
Performance issues can be complex. Our Discord community has experienced server developers who can help diagnose specific problems. If you want a job system that sets the standard for resmon efficiency, check out Jobs Creator by Alone Studios — built from the ground up for zero-impact performance.
Ready to Transform Your Server?
FiveM Job Creator eliminates every problem discussed in this article. 0.00ms resmon. No-code configuration. ESX & QBCore native.
Get Job Creator on Tebex — €29.99