Skip to content
All Articles

ESX Performance Optimization: Where to Start

Your server lags at 80 players but you don't know why. Here's a practical approach to finding and fixing the real bottlenecks in ESX-based FiveM servers.

PerformanceESXOptimization

Why Your Server Lags

Server performance problems in FiveM are almost never about hardware. They’re about how your scripts use resources. A single badly written loop or an unindexed database query can tank your entire server.

The good news: most performance issues follow predictable patterns. Here’s where to look first.

Measure Before You Optimize

Before changing anything, you need data. Use resmon (resource monitor) to identify which scripts consume the most server-side milliseconds per tick.

resmon 1

Sort by server-side time. Anything consistently above 1ms deserves investigation. Your total server frame time should stay under 16ms (for a 64-tick server) to avoid lag.

The Top 3 Performance Killers

1. Polling Loops Without Throttling

Many scripts use Citizen.CreateThread with Citizen.Wait(0) — running every single frame. Most of them don’t need to.

Example: A script that checks if a player is near a blip every frame. At 64 ticks/second across 100 players, that’s 6,400 checks per second — for something that changes every few seconds at most.

Fix: Increase the wait time based on how often the check actually needs to happen.

Citizen.CreateThread(function()
  while true do
    local sleep = 1000
    local coords = GetEntityCoords(PlayerPedId())
    
    if #(coords - targetCoords) < 50.0 then
      sleep = 100 -- check more often when close
    end
    
    Citizen.Wait(sleep)
  end
end)

2. Database Queries in Hot Paths

Running a database query every time a player does something common (picking up an item, opening a menu, moving between zones) is a performance disaster at scale.

Fix:

  • Cache frequently accessed data in memory
  • Batch writes instead of writing every change immediately
  • Ensure your database has proper indexes on commonly queried columns
-- Add indexes for common lookups
CREATE INDEX idx_users_identifier ON users(identifier);
CREATE INDEX idx_owned_vehicles_owner ON owned_vehicles(owner);

3. Excessive Network Events

Every TriggerClientEvent and TriggerServerEvent uses bandwidth and processing time. Scripts that fire events every frame or broadcast to all players unnecessarily create bottleneck.

Fix:

  • Use -1 (all players) only when genuinely needed
  • Batch small updates into periodic syncs
  • Use state bags for data that changes frequently

Quick Wins

These changes take minutes but can have significant impact:

  • Remove unused scripts: Every loaded resource uses memory and startup time, even if it does nothing
  • Update oxmysql: Older mysql-async versions are significantly slower
  • Disable debug prints in production: print() calls in hot loops are surprisingly expensive
  • Use server-side entity creation: Client-side object spawning at scale causes desync

When to Get Help

If resmon shows high total frame times but no single script stands out, the problem is often cumulative — many scripts each adding a small amount. That’s harder to diagnose without profiling tools and experience.

A Full Audit includes script-by-script profiling and specific recommendations for your setup.


Need help with your server?

We audit, fix, and optimize FiveM servers. Get started with a Quick Audit.

Start Audit